Theming

Every component is styled against CSS variables - never hard-coded colors. That means two independent axes: the mode (light / dark) and the design theme (the palette and radius). Change the variables, and every component follows.

Try it now: use the palette and mode switchers in the top-right of this page. Everything re-skins live - that’s the token system at work.

Light, dark & system

Mode is the dark class on <html>. The ThemeProvider manages it - light, dark, or following the OS - and a tiny inline script sets it before paint, so there’s no flash.

import { ThemeProvider } from "@/components/theme/theme-provider";

<ThemeProvider>{children}</ThemeProvider>

// Components read tokens that flip under .dark automatically:
// :root { --background: #fbfbfc }  .dark { --background: #000 }

Design themes

Flagon ships a default theme plus a few alternates - Flagon, Indigo, Rose, and Mono. A theme is just a set of token overrides applied with a data-theme attribute; it composes with light/dark.

// Scope a theme to any subtree - the default (Flagon) needs no attribute.
<div data-theme="indigo">
  <Button>Now indigo</Button>
</div>

Tokens

The vocabulary follows shadcn’s naming, so it’s portable, with a few brand extras.

--background / --foreground
Page surface and text
--card / --popover
Raised surfaces (cards, menus)
--primary
Primary action color
--secondary / --muted / --accent
Subtle surfaces
--destructive
Errors and destructive actions
--border / --input / --ring
Hairlines, field borders, focus rings
--brand / --brand-bright / --link
Flagon brand accents
--radius
Base corner radius

Create your own theme

Override the tokens under a selector - your own brand, a per-tenant theme, whatever. Give light values on the base selector and dark values under .dark.

[data-theme="acme"] {
  --primary: #7c3aed;
  --ring: #7c3aed;
  --brand: #7c3aed;
  --brand-bright: #6d28d9;
  --radius: 0.75rem;
}
.dark [data-theme="acme"] {
  --primary: #a78bfa;
  --brand-bright: #c4b5fd;
}