Custom Themes
The createTheme() utility lets you build a brand-specific theme by overriding only the values that differ from a built-in base. Everything you don’t override inherits from the base theme.
The createTheme() utility
Section titled “The createTheme() utility”import { createTheme } from '@/tokens/themes/createTheme';createTheme(base, overrides) performs a deep merge — you only need to specify the keys that change.
Example: brand accent color
Section titled “Example: brand accent color”The most common customisation is swapping the accent color:
import { createTheme } from '@/tokens/themes/createTheme';import { slateThemeLight, slateThemeDark } from '@/tokens/themes/slate';
export const brandLight = createTheme(slateThemeLight, { colors: { accent: '#E11D48', // rose accentHover: '#BE123C', accentSubtle: '#FFF1F2', },});
export const brandDark = createTheme(slateThemeDark, { colors: { accent: '#FB7185', accentHover: '#F43F5E', accentSubtle: '#4C0519', },});Registering the custom theme
Section titled “Registering the custom theme”Add one entry to THEME_REGISTRY:
import { brandLight, brandDark } from './brand';
export const THEME_REGISTRY = [ // ... existing themes { name: 'brand', label: 'Brand', light: brandLight, dark: brandDark },];That’s it. setTheme('brand') now works. TypeScript infers the 'brand' name from the registry automatically.
What you can override
Section titled “What you can override”Any key in the AppTheme interface can be overridden:
export const customTheme = createTheme(slateThemeLight, { colors: { accent: '#0EA5E9', accentHover: '#0284C7', accentSubtle: '#F0F9FF', }, radius: { md: 12, // rounder corners than Slate's 8 }, buttonShape: 'default', // square instead of pill iconWeight: 'bold', // heavier icons});Color philosophy
Section titled “Color philosophy”Stratum is designed around one accent hue per theme. Resist adding a second accent — secondary buttons use ghost or outline treatments of the same accent. Signal colors (success, warning, error) appear only for status — never as decoration.
If your brand requires a second color (e.g., a separate destructive hue), extend the AppTheme interface in theme-protocol.ts and add the new slot to all theme files.
Related
Section titled “Related”- Theme Registry — how THEME_REGISTRY works
- Theming — AppTheme interface reference
- Slate — clean base for most brand themes
- Obsidian — structural base for editorial brands