Theming
Apply your brand accents after installing the design system styles, including multi-brand palettes.
Installed components read semantic CSS tokens such as primary, ring, and sidebar-primary. After you install styles, you brand the product by changing those tokens — not by editing component source.
Theme files
globals.css pulls in the default tokens and optional accent palettes:
@import "./theme.css";
@import "./theme-secondary.css";
@import "./theme-tertiary.css";| File | When it applies |
|---|---|
theme.css | Default palette on :root and .dark |
theme-secondary.css | When data-theme="theme-secondary" |
theme-tertiary.css | When data-theme="theme-tertiary" |
With no data-theme attribute, the app stays on the default tokens in theme.css. Accent files only override the brand-facing tokens (--primary, --ring, --sidebar-primary, --selection, and --chart-*). Surfaces such as --background and --foreground stay on the default palette.
Light and dark mode still use the .dark class. Each accent file includes a .dark[data-theme="…"] block so the brand color can shift in dark mode.
Use a shipped accent
Set data-theme on the root element in your layout so the palette is present on first paint:
<html lang="en" data-theme="theme-secondary">theme-secondary is amber and theme-tertiary is violet. To let users switch palettes, install Theme Toggle.
Use your own brand color
Pick one of these approaches.
Edit the default tokens
For a single-brand app that does not need named palettes, change the accent tokens in src/styles/theme.css under :root and .dark:
:root {
--primary: oklch(0.55 0.19 250);
--primary-foreground: oklch(0.985 0 0);
--ring: oklch(0.55 0.19 250);
--sidebar-primary: oklch(0.55 0.19 250);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-ring: oklch(0.55 0.19 250);
--selection: oklch(0.55 0.19 250);
--selection-foreground: oklch(0.985 0 0);
}Leave data-theme unset. Buttons, focus rings, and other primary styles pick up the new values.
Add a named palette
To keep the default palette and add your brand as a selectable accent, create a file next to the shipped themes — for example src/styles/theme-brand.css:
[data-theme="theme-brand"] {
--primary: oklch(0.55 0.19 250);
--primary-foreground: oklch(0.985 0 0);
--ring: oklch(0.55 0.19 250);
--sidebar-primary: oklch(0.55 0.19 250);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-ring: oklch(0.55 0.19 250);
--selection: oklch(0.55 0.19 250);
--selection-foreground: oklch(0.985 0 0);
--chart-1: oklch(0.55 0.19 250);
--chart-2: oklch(0.6 0.16 220);
--chart-3: oklch(0.65 0.12 190);
--chart-4: oklch(0.5 0.2 270);
--chart-5: oklch(0.7 0.1 230);
}
.dark[data-theme="theme-brand"] {
--primary: oklch(0.72 0.16 248);
--primary-foreground: oklch(0.145 0 0);
--ring: oklch(0.72 0.16 248);
--sidebar-primary: oklch(0.72 0.16 248);
--sidebar-primary-foreground: oklch(0.145 0 0);
--sidebar-ring: oklch(0.72 0.16 248);
--selection: oklch(0.72 0.16 248);
--selection-foreground: oklch(0.145 0 0);
--chart-1: oklch(0.72 0.16 248);
--chart-2: oklch(0.75 0.14 218);
--chart-3: oklch(0.78 0.11 188);
--chart-4: oklch(0.65 0.18 268);
--chart-5: oklch(0.82 0.09 228);
}Import it from globals.css with the other theme files:
@import "./theme.css";
@import "./theme-secondary.css";
@import "./theme-tertiary.css";
@import "./theme-brand.css";Then set the matching attribute:
<html lang="en" data-theme="theme-brand">You can also replace the values in theme-secondary.css or theme-tertiary.css instead of adding a new file. The selector name (theme-secondary) and the data-theme value must match.
Multi-brand teams
Named accent palettes are for teams that ship more than one product, partner, or white-label from the same component set. Each brand is a CSS file that only overrides accent tokens; buttons, focus rings, and charts restyle without forking components or duplicating layouts.
That is useful when:
- Several products share density, type, and surfaces (
--background,--foreground,--muted) but need distinct--primarycolors. - A platform app switches brand per tenant, environment, or route by setting
data-themeon<html>at render time. - Designers and engineers preview every brand on one docs or Storybook surface, using Theme Toggle or a
data-themeattribute on a subtree. Because the selectors are[data-theme="…"]rather than:rootonly, a nested region can use a different accent than the rest of the page.
Keep one palette file per brand (theme-acme.css, theme-partner.css) and import them all from globals.css. The shared component library stays the source of truth; brand teams own only their token file.
Accent tokens
Override this set when you brand an accent. Copy the same keys into both the light and .dark blocks.
| Token | Typical use |
|---|---|
--primary | Buttons, key actions, brand fills |
--primary-foreground | Text and icons on --primary |
--ring | Focus rings |
--sidebar-primary | Sidebar brand and active states |
--sidebar-primary-foreground | Text on --sidebar-primary |
--sidebar-ring | Sidebar focus rings |
--selection | Text selection background |
--selection-foreground | Text selection foreground |
--chart-1 … --chart-5 | Chart series colors |