Theme
The color scheme dimension — light and dark modes.
Definition
Theme controls the overall color scheme — light or dark mode. It is an environmental dimension that affects the entire application or a scoped section.
Values
| Value | Meaning |
|---|---|
light | Light color scheme |
dark | Dark color scheme |
Default: project-dependent
Theme as an Environmental Dimension
Unlike dimensions such as emphasis or sentiment, theme is not a property of individual components. It is an environmental setting — a context that surrounds components and influences how their tokens resolve.
A button does not know whether it is in light or dark mode. It references semantic tokens, and the environment determines which concrete values those tokens return. This distinction keeps component code entirely theme-unaware.
| Dimension type | Scope | Example |
|---|---|---|
| Component dimension | Single component instance | emphasis, size |
| Environmental dimension | Region or entire app | theme |
Token Resolution
Theme relies on a two-layer token model: primitives and semantics.
Primitives are raw values scoped to a theme. They define the palette available in each mode:
/* Light primitives */
[data-theme="light"] {
--color-neutral-0: #ffffff;
--color-neutral-900: #111111;
}
/* Dark primitives */
[data-theme="dark"] {
--color-neutral-0: #111111;
--color-neutral-900: #ffffff;
}Semantic tokens reference primitives via var(). They describe intent, not color:
:root {
--color-surface: var(--color-neutral-0);
--color-text: var(--color-neutral-900);
}When the theme changes, primitive values swap. Semantic tokens automatically resolve to the new primitives through the CSS cascade — no additional logic required.
| Layer | Role | Changes with theme? |
|---|---|---|
| Primitive | Defines raw color values per mode | Yes |
| Semantic | Describes purpose, references primitives | No |
Mode Structure in Figma
Figma variable collections mirror this two-layer model. A Primitives collection contains raw color values with modes for each theme:
| Variable | Light | Dark |
|---|---|---|
neutral/0 | #ffffff | #111111 |
neutral/900 | #111111 | #ffffff |
A Semantics collection references primitives by alias. Because Figma resolves aliases per mode, switching a frame's mode from Light to Dark updates every semantic variable — exactly as var() resolution works in CSS.
This parallel structure means designers and developers share the same mental model: one set of semantic names, two sets of underlying values.
Runtime Theme Switching
Switching themes at runtime requires changing a single data attribute on a container element:
[data-theme="dark"] { /* dark primitive values */ }
[data-theme="light"] { /* light primitive values */ }// Toggle theme
document.documentElement.dataset.theme =
document.documentElement.dataset.theme === "light" ? "dark" : "light";Because semantic tokens reference primitives through var(), the CSS cascade handles the rest. No component re-renders, no conditional class logic, no theme prop drilling. Every component automatically reflects the new theme.
Scoped Theming
Because themes are applied via data attributes, they can be scoped to any section of the page. A container with a different data-theme value creates a localised theme boundary:
<body data-theme="light">
<!-- Light theme content -->
<aside data-theme="dark">
<!-- Dark sidebar — tokens resolve to dark primitives -->
</aside>
</body>Scoped theming works because CSS custom property inheritance respects the nearest ancestor. The aside and its descendants resolve primitives from the dark scope, while the rest of the page stays light.
This enables patterns like dark navigation bars, inverted hero sections, or preview panels — all without duplicating component variants.
Relationship with Other Dimensions
Theme is independent of all other dimensions. A component can combine any state, emphasis, sentiment, or size with any theme:
Button[state=hover, emphasis=high, sentiment=warning, theme=dark]The theme dimension only affects which primitive values the semantic tokens resolve to. All other dimensions operate on the semantic layer and are unaffected by theme changes.
This independence is what makes the dimensional model composable — adding a new theme does not require updating any component variant, only defining a new set of primitive values.