The theme system
UX separates two choices: mode selects light, dark, or system preference; palette selects the visual direction. Components use semantic CSS variables so both choices apply throughout the interface.
Try the theme system#
Your product, in character.
The same controls and state follow the selected palette.
Preview tokens are scoped to this example; the documentation theme stays yours.
Set up the provider#
TSX
import { ThemeProvider } from '@clidey/ux';
import '@clidey/ux/styles.css';
import '@clidey/ux/theme-fonts.css';
<ThemeProvider defaultTheme="system" defaultPalette="paper-ink">
<App />
</ThemeProvider>
The font stylesheet is optional. It references the package's own WOFF2 assets; you do not need a second font bundle in your repository.
Provider props#
| Prop | Type | Default | Behavior |
|---|---|---|---|
defaultTheme | "light", "dark", "system" | "system" | Initial preference when there is no valid saved mode. |
storageKey | string | "@clidey/ux/theme" | Local storage key for mode. |
defaultPalette | string | Omitted | Initial catalog palette when there is no valid saved palette. |
paletteStorageKey | string | "@clidey/ux/palette" | Local storage key for palette. |
children | ReactNode | Required | Application content. |
Omit the palette to use the base CSS tokens. Saved preferences take precedence over defaults. Use application-specific storage keys when several products share an origin.
Change either choice#
TSX
import { Button, ModeToggle, useTheme } from '@clidey/ux';
export function AppearanceActions() {
const { setPalette } = useTheme();
return <>
<ModeToggle />
<Button variant="outline" onClick={() => setPalette('forest-moss')}>
Try Forest Moss
</Button>
<Button variant="ghost" onClick={() => setPalette(null)}>
Use base tokens
</Button>
</>;
}
Call useTheme inside the provider. It returns theme, setTheme, palette, and setPalette. Mode values describe the user's preference: "system" remains "system" even while the resolved document mode is light or dark.
What happens on the document#
The provider applies the resolved light or dark class to the document root. A selected palette adds its class and data-theme value, and applies its typography and motion properties. System mode listens for operating-system preference changes. Changes made through the hook are persisted locally.
Use semantic roles in custom surfaces instead of fixed colors. Changing a theme cannot update a hardcoded white background or an inline hex color in application markup.
Go deeper#
- 30 palettes, one application: browse the catalog and build a picker.
- Semantic tokens: style layouts and brand overrides.
- Typography and motion: use the palette's type and transition choices.
- Dark mode: test system preference and custom controls.
- Framework integration: client boundaries and CSS ordering.
Was this page helpful?
