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>
ThemeAccentFont pairing (display / body)Appearance
DefaultMonochromeSpace Grotesk / Interdark
LinearVioletInter / Interdark
NordicTealOutfit / Interlight
VanguardRedSpace Grotesk / Interdark
CyberLimeJetBrains Mono / Interdark
WiseOwlLimePublic Sans / Interdark
EditorialBronzeFraunces / Interlight
Neo TokyoRubySpace Grotesk / Interdark
OasisJadeOutfit / Interlight
OceanMintSpace Grotesk / Interlight
VelvetPlumPlayfair Display / Interdark
MinimalMonochromeOutfit / Interlight
WarmAmberLora / Interlight
PlayfulIrisSpace Grotesk / Space Grotesklight
SunsetCrimsonOutfit / Interdark
MidnightCyanSpace Grotesk / Interdark
TerminalGreenJetBrains Mono / JetBrains Monodark

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.

Gotcha: In dark mode, accent swatches automatically adjust contrast levels, ensuring buttons remain completely legible.

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>
  );
}
Configure Theme
Theme
Accent Color
Custom
Gray Family
Appearance
Radius
Scaling
Panel Style
Heading Font
Body Font