Theming guide
Brand an entity with one color.
One color fills the whole brand ramp, so buttons, focus rings, selection, tints, and dark mode all follow it. Set it in one CSS block or on DgaProvider.
The 12-step ramp from one color, --ddga-brand-foreground, and the contrast warning need @dev-dga/react, @dev-dga/css, and @dev-dga/tokens 1.6.0 or later.
Brand an entity in one CSS block
Set your entity color once and derive the 12 --ddga-brand-* steps from it with color-mix(). The color is step 600. Lighter steps mix it with white and darker steps with black, in the same proportions as the built-in palettes. No JavaScript runs.
Put the block after the @dev-dga/css import and outside any @layer. The library declares its variables in the ddga-base layer, and unlayered styles win over layered ones. Don’t also pass theme to DgaProvider: its inline values win over the block.
Light mode: primary is step 600
Dark mode: primary is step 400
Which step each role reads
Components read role variables, never the steps themselves. Each role points at a step of the brand ramp, and dark mode moves it to a lighter step so it stays legible on dark surfaces.
| Role | Light mode | Dark mode |
|---|---|---|
--ddga-color-primary | --ddga-brand-600 | --ddga-brand-400 |
--ddga-color-primary-hover | --ddga-brand-700 | --ddga-brand-300 |
--ddga-color-primary-active | --ddga-brand-900 | --ddga-brand-500 |
--ddga-color-ring | --ddga-brand-600 | --ddga-brand-400 |
--ddga-color-primary-foreground | --ddga-brand-foreground | --ddga-gray-950 |
Without --ddga-brand-foreground, text on primary is white in light mode. The roles resolve at :root and on every element with data-theme. DgaProvider sets data-theme on its root, so dark mode reads the same ramp.
Check the text on primary buttons
In light mode, primary buttons show white text on your color. If white doesn’t reach 4.5:1 on it, as with a yellow or a light green, set --ddga-brand-foreground to dark text. Dark mode always uses gray-950 text on step 400.
In development, DgaProvider warns when a theme color fails 4.5:1, but a CSS block never reaches the provider. Check your color in a contrast checker before you ship.
Set the color on DgaProvider
theme.primary takes the same color and builds the same 12 steps, or takes a built-in palette name. Use it when the color comes from data, such as a per-entity setting.
For server rendering or a scoped area, buildTheme returns the same variables as a plain object. Spread it on an element that carries data-theme.
To tune tokens beyond the brand ramp, use the Theme studio
Upgrading from 1.5
Apps that already pass a color to theme.primary see these changes:
- Tints, focus rings, selection, and dark mode follow your color instead of SA Green.
- Hover is step 700 and pressed is step 900, slightly different from the old color-mix(in srgb) values.
- Dark mode shows gray-950 text on primary fills instead of white, for palettes and custom colors.
- In light mode, the warning and success palettes switch to gray-950 text.
- buildTheme with a color returns only --ddga-brand-* values; spread it on an element with data-theme.
- The explicit { base, hover, active, foreground } triplet is unchanged.