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;
}