How the token cascade works
Anvil2 tokens are organized in three tiers: primitives (raw values), semantic tokens (values with purpose — e.g.background.color.primary), and component tokens (values scoped to one component — e.g. button.primary.background.color). Each tier references the tier below it: component tokens reference semantic tokens, and semantic tokens reference primitives. Tiers are never skipped.
Overriding a token fans out to everything that references it. Override background.color.primary and every component that consumes it — Button, Alert, Badge, and many more — updates together. Override button.primary.background.color and only Button changes. Primitive overrides do not cascade at runtime; see Cascading limitations below.
Overriding at the semantic level (tier 2)
Use this for bulk theming — reshaping the design system to match a product brand. The standard way isThemeProvider:
Overriding at the component level (tier 3)
Use this to customize a single component without touching anything else. Same shape as semantic overrides, with acomponent object:
/tokens tab.
Cascading limitations
Tier-1 primitive overrides don’t cascade at runtime. Component and semantic tokens embed the resolved primitive value at build time (vialight-dark()), so changing ColorBlue500 through ThemeProvider has no effect on BackgroundColorPrimary or ButtonPrimaryBackgroundColor. Override at tier 2 or tier 3 instead.
Prefer ThemeProvider over raw CSS variables. ThemeProvider kebabizes keys, prefixes with --a2-, and wraps light/dark values in light-dark() automatically. A raw CSS override has to do all three manually and drops dark mode support if only a light value is supplied.
Dark mode
Design
Anvil2 Figma assets use variables for light and dark mode. Refer to Figma’s guidance on how to switch between modes.Code
Toggle app-wide mode viaAnvilProvider:
AnvilProvider includes a ThemeProvider under the hood. To change the theme of part of a page without affecting the rest, use ThemeProvider directly:
How light-dark() works under the hood
Every themed CSS variable is authored as light-dark(<light>, <dark>). The ThemeProvider component flips which branch is live by applying a .mode-light or .mode-dark class that sets color-scheme: light or dark on the subtree:
light-dark() against color-scheme, so toggling the class is enough — no JavaScript re-render of styles is needed.
How ThemeProvider picks up dark values automatically
When you override a token without supplying a dark value, ThemeProvider falls back to the base token’s extensions.appearance.dark.value for the dark branch. In practice this means you can write a single-value light override and dark mode keeps working.
Related
- Design Tokens — complete tier and category reference.
- Each component’s
/tokenspage lists its tier-3 tokens and override examples.