Theming Guide

Vultra UI uses CSS custom properties for theming. This guide covers advanced patterns beyond the basics.

Anatomy of a Theme

Every theme is a CSS file that redefines the same variables:

/* Custom theme: brand.css */
@import "@vultra/tokens/base";

:root {
  --ui-background: oklch(0.98 0.01 240);
  --ui-foreground: oklch(0.2 0.02 240);
  --ui-primary: oklch(0.55 0.2 265);
  --ui-primary-foreground: oklch(1 0 0);
  --ui-radius: 0.75rem;
}

Import it instead of the base theme:

/* app.css */
@import "@vultra/tokens/brand.css"; /* your custom theme */

Dark Mode with Two Themes

Stack themes with a class toggle:

/* app.css */
@import "@vultra/tokens/base";

html.dark {
  --ui-background: oklch(0.15 0.01 240);
  --ui-foreground: oklch(0.95 0 0);
  --ui-primary: oklch(0.7 0.15 265);
  --ui-card: oklch(0.2 0.01 240);
}
// Theme toggle
const theme = localStorage.getItem('theme') ?? 'light';
document.documentElement.classList.toggle('dark', theme === 'dark');

function toggle() {
  const dark = document.documentElement.classList.toggle('dark');
  localStorage.setItem('theme', dark ? 'dark' : 'light');
}

All Variables

VariablePurpose
--ui-backgroundPage background
--ui-foregroundDefault text
--ui-cardCard surface
--ui-card-foregroundCard text
--ui-primaryPrimary action color
--ui-primary-foregroundText on primary
--ui-secondarySecondary surface
--ui-mutedMuted surface
--ui-muted-foregroundMuted text
--ui-accentAccent color
--ui-borderBorder color
--ui-ringFocus ring
--ui-radiusBorder radius
--ui-shadow-sm/md/lg/xlShadow levels

Building a Custom Theme

  1. Start from a base — copy @vultra/tokens/base or any theme
  2. Override semantic colors — keep the variable names, change values
  3. Test contrast — foreground on background, primary on primary-foreground
  4. Export — publish as @your-brand/tokens for your team

Theme Recipes

Minimal

:root {
  --ui-radius: 0.25rem;
  --ui-background: oklch(0.99 0 0);
  --ui-primary: oklch(0.25 0 0);
  --ui-primary-foreground: oklch(0.99 0 0);
  --ui-border: oklch(0.9 0 0);
}

Warm

:root {
  --ui-background: oklch(0.98 0.01 80);
  --ui-primary: oklch(0.6 0.15 45);
  --ui-border: oklch(0.9 0.02 80);
}

High Contrast

:root {
  --ui-background: oklch(1 0 0);
  --ui-foreground: oklch(0 0 0);
  --ui-primary: oklch(0 0 0);
  --ui-primary-foreground: oklch(1 0 0);
  --ui-radius: 0;
}

Next Steps