Theme System
Dynamic Swatch Configurations
Shavin UI ships with 24 distinct accent color palettes, 5 grayscales, and sizing scale factors. To load a specific theme preset configuration, wrap your root elements inside the ThemeProvider context wrapper:
import { ThemeProvider } from "@shavin/ui";
export default function App() {
return (
<ThemeProvider
accentColor="grass"
grayColor="zinc"
radius="medium"
scaling="95%"
panelBackground="translucent"
>
<MainLayout />
</ThemeProvider>
);
}Theme presets
Skip the individual props — pass a single theme to load a curated brand config: accent, neutrals, radius, density, panel style, and a display/body font pairing. Add individual props alongside to override any of it.
import { ThemeProvider } from "@shavin/ui";
<ThemeProvider theme="Editorial">
<App />
</ThemeProvider>| Theme | Accent | Font pairing (display / body) | Appearance |
|---|---|---|---|
| Default | Monochrome | Space Grotesk / Inter | dark |
| Linear | Violet | Inter / Inter | dark |
| Nordic | Teal | Outfit / Inter | light |
| Vanguard | Red | Space Grotesk / Inter | dark |
| Cyber | Lime | JetBrains Mono / Inter | dark |
| WiseOwl | Lime | Public Sans / Inter | dark |
| Editorial | Bronze | Fraunces / Inter | light |
| Neo Tokyo | Ruby | Space Grotesk / Inter | dark |
| Oasis | Jade | Outfit / Inter | light |
| Ocean | Mint | Space Grotesk / Inter | light |
| Velvet | Plum | Playfair Display / Inter | dark |
| Minimal | Monochrome | Outfit / Inter | light |
| Warm | Amber | Lora / Inter | light |
| Playful | Iris | Space Grotesk / Space Grotesk | light |
| Sunset | Crimson | Outfit / Inter | dark |
| Midnight | Cyan | Space Grotesk / Inter | dark |
| Terminal | Green | JetBrains Mono / JetBrains Mono | dark |
Font pairings load from Google Fonts on demand. Tweak any control in the Configurator (top-right) and the preset auto-switches to “Custom”.
Presets List Options
The following runtime presets are fully supported and mapped inside our theme manifest:
Accent Swatches
Choose between named presets like grass, tomato, amber, iris, indigo, and gold. Alternatively, supply an arbitrary brand color hex (like #ff0088).
Gray Swatches
Select an interface grayscale family to match your accent palette: gray, mauve, slate, sage, or zinc.
Radii Presets
Configure component border radii: none (0px), small (4px), medium (8px), large (12px), or full (stadium-shaped).
Scale Multipliers
Adjust spacing densities to fit layouts: 90%, 95%, 100%, 105%, or 110%.
Appearance states
Light and dark states are driven by toggling the standard .dark class on parent wrapper wrappers. The design system reads variables dynamically, allowing layout colors to adjust seamlessly.
Scoped Theming (Local Subtrees)
When you need a specific container, card preview, interactive sandbox, or embedded section to render with its own theme parameters without altering the global application :root, use scopedThemeVars().
This function generates the exact CSS custom property dictionary for the target configuration. Spread it directly into your element's style object alongside any additional inline styles:
import { scopedThemeVars, Button, Card, Badge } from "@shavin/ui";
export function ScopedPreview() {
// Generate CSS custom properties dictionary for a specific theme setup
const themeVars = scopedThemeVars(
// ds-lint-disable-next-line no-hex — example config shows default accent hex
"#bdee63", // accent color (preset name or hex)
"Zinc", // gray family (Gray, Mauve, Slate, Sage, Zinc)
"large", // radius preset (none, small, medium, large, full)
true, // isDark (true | false)
"JetBrains Mono", // display font
"Inter", // body font
100 // scaling percentage (90 - 110)
);
return (
<div
style={{
...(themeVars as React.CSSProperties),
minHeight: "320px",
}}
className="dark p-6 rounded-[var(--radius-panel)] border border-hairline bg-canvas"
data-theme="dark"
>
<Card padding="md" className="flex flex-col gap-3">
<Badge color="accent">Scoped Theme</Badge>
<p className="text-fg font-medium">This subtree uses isolated tokens.</p>
<Button variant="solid" tone="accent">Accent Action</Button>
</Card>
</div>
);
}