Customization
Zen uses CSS custom properties (variables) for all design tokens, making it easy to customize the look and feel of your application. You can override these variables to match your brand or create entirely custom themes.
Overriding variables#
To customize Zen, override the CSS variables in your stylesheet. Variables defined on :root apply globally, while scoped selectors can target specific themes.
Creating a branded theme#
Here's an example of creating a custom branded theme with a blue accent:
CSS variable reference#
Primary#
The primary accent color used for primary buttons and branded elements.
| Variable | Description |
|---|---|
| --zen-primary | Primary/brand accent color (button backgrounds) |
| --zen-primary-fg | Text color on primary backgrounds |
Surfaces#
Background colors for different elevation levels.
| Variable | Description |
|---|---|
| --zen-surface | Primary background (page level) |
| --zen-surface-raised | Elevated surfaces (cards, modals) |
| --zen-surface-sunken | Recessed areas (inputs, wells) |
| --zen-surface-overlay | Overlays (dropdowns, popovers) |
| --zen-surface-inverted | Inverted background (tooltips) |
| --zen-surface-disabled | Disabled element background |
Text#
Text colors for different emphasis levels.
| Variable | Description |
|---|---|
| --zen-fg | Primary text (headings, body) |
| --zen-fg-muted | Muted text (labels, placeholders, hints) |
| --zen-fg-disabled | Disabled text |
Borders#
Border colors for different emphasis levels.
| Variable | Description |
|---|---|
| --zen-border | Default border (inputs, cards) |
| --zen-border-muted | Subtle borders (dividers) |
| --zen-border-strong | Emphasized borders (focus, active) |
Interactive states#
Colors for interactive elements like buttons, checkboxes, and list items.
| Variable | Description |
|---|---|
| --zen-interactive-bg | Default interactive background |
| --zen-interactive-bg-hover | Hover state background |
| --zen-interactive-bg-pressed | Pressed/active state background |
Focus#
Focus ring styles for accessibility.
| Variable | Description |
|---|---|
| --zen-focus-ring | Focus ring color |
| --zen-focus-offset | Focus ring offset color (gap) |
Status colors#
Colors for feedback states (info, success, warning, error).
| Variable | Description |
|---|---|
| --zen-status-info | Info accent color |
| --zen-status-info-bg | Info background |
| --zen-status-info-fg | Info text color |
| --zen-status-success | Success accent color |
| --zen-status-success-bg | Success background |
| --zen-status-success-fg | Success text color |
| --zen-status-warning | Warning accent color |
| --zen-status-warning-bg | Warning background |
| --zen-status-warning-fg | Warning text color |
| --zen-status-error | Error accent color |
| --zen-status-error-bg | Error background |
| --zen-status-error-fg | Error text color |
Typography#
Font family variables.
| Variable | Description |
|---|---|
| --zen-font-family | Default font stack |
| --zen-font-family-mono | Monospace font stack |
Using OKLCH colors#
Zen uses OKLCH color values for better color manipulation and perceptual uniformity. OKLCH colors are defined as oklch(lightness chroma hue):
- Lightness: 0 (black) to 1 (white)
- Chroma: 0 (gray) to ~0.4 (vivid)
- Hue: 0-360 degrees (color wheel)
Tips#
- Always provide both light and dark theme overrides for a consistent experience
- Use OKLCH for colors to maintain perceptual consistency across themes
- Test your customizations in both themes to ensure adequate contrast
- Use browser DevTools to inspect and experiment with CSS variables in real-time
Token naming#
All Zen tokens use the --zen- prefix. Unsuffixed names represent the default value;
variants add a suffix, such as --zen-border-muted. Foreground colors use fg, and
background qualifiers use bg. The --zen-palette-50 through --zen-palette-950 tokens
provide the selected neutral, slate, gray, zinc, or stone shades used by semantic colors.
Migrating token names#
Update custom overrides and utility classes to the names below. Token values and light/dark palette definitions are unchanged. The old names are no longer provided.
| Previous token | Current token |
|---|---|
--zen-radius-default | --zen-radius |
--zen-shadow-default | --zen-shadow |
--zen-padding-x-default | --zen-padding-x |
--zen-padding-y-default | --zen-padding-y |
--zen-gap-default | --zen-gap |
--zen-surface-base | --zen-surface |
--zen-border-default | --zen-border |
--zen-text-primary | --zen-fg |
--zen-text-muted | --zen-fg-muted |
--zen-text-disabled | --zen-fg-disabled |
--zen-primary-foreground | --zen-primary-fg |
--zen-status-*-text | --zen-status-*-fg |
--zen-focus-ring-offset | --zen-focus-offset |
--zen-gray-* | --zen-palette-* |
| Previous utility | Current utility |
|---|---|
bg-surface-base | bg-surface |
text-surface-base | text-surface |
text-foreground / text-foreground-primary | text-fg |
text-foreground-muted | text-fg-muted |
text-foreground-disabled | text-fg-disabled |
text-primary-foreground | text-primary-fg |
text-status-*-text | text-status-*-fg |
The surface color prop value also changes: use backgroundColor="surface" instead of
backgroundColor="surface-base". Responsive values and hover/focus/active variants
use the same new names. border-edge and ring-offset-focus-offset remain unchanged.
The package's Tailwind preset and its own build now share one configuration, including
the correct --zen- variable references.
