Live preview · measured contrast · CSS out
Theme generator
An accent, a neutral ladder, a radius, a face and a rhythm. A real dashboard page repaints as you go, every text tier’s contrast is measured on every plane it sits on, and the theme copies out as CSS.
Contrast, measured
Each text tier on each plane it sits on, from the tokens the export writes, by WCAG 2’s ratio — and the full suite CI runs on the kit’s own palettes: light 122 of 122 · dark 122 of 122 pass.
| Text | Background--background | Card--card | Muted--muted | Brand muted--brand-muted | Accent--accent |
|---|---|---|---|---|---|
| Foreground--foreground4.5:1 floor | 19.79:1Pass | 19.79:1Pass | 17.88:1Pass | 16.10:1Pass | 17.88:1Pass |
| Muted text--muted-foreground4.5:1 floor | 6.00:1Pass | 6.00:1Pass | 5.42:1Pass | 4.88:1Pass | 5.42:1Pass |
| Subtle text--faint-foreground4.5:1 floor | 5.74:1Pass | 5.74:1Pass | 5.19:1Pass | 4.67:1Pass | 5.19:1Pass |
| Accent text--brand4.5:1 floor | 17.91:1Pass | 17.91:1Pass | 16.18:1Pass | 14.57:1Pass | 16.18:1Pass |
Text on accent--brand-foreground on --brand4.5:1 floor
17.15:1Pass
Export
Every token the generator sets and nothing it does not, in both modes. Paste the first over the palette in your globals.css; the second wears the same values on any wrapper.
/* Vibra theme. Edit it again: https://vibraui.com/themes/generator?accent=0.205_0_0&neutral=neutral&radius=0.625&font=sans&density=comfortable&chart=accent&mode=light */:root { --radius: 0.625rem; /* Planes. */ --background: oklch(1 0 0); --surface: oklch(0.985 0 0); --card: oklch(1 0 0); --popover: oklch(1 0 0); --muted: oklch(0.965 0 0); --secondary: oklch(0.965 0 0); --accent: oklch(0.965 0 0); /* Ink. */ --foreground: oklch(0.145 0 0); --card-foreground: oklch(0.145 0 0); --popover-foreground: oklch(0.145 0 0); --muted-foreground: oklch(0.5 0 0); --faint-foreground: oklch(0.51 0 0); --secondary-foreground: oklch(0.205 0 0); --accent-foreground: oklch(0.205 0 0); /* The accent. */ --brand: oklch(0.205 0 0); --brand-foreground: oklch(0.985 0 0); --brand-muted: oklch(0.93 0 0); /* Lines. */ --border: oklch(0.905 0 0); --rule: oklch(0.87 0 0); --input: oklch(0.63 0 0); --chart-grid: oklch(0.905 0 0); /* Charts. */ --chart-1: oklch(0.66 0 0); --chart-2: oklch(0.55 0.19 258); --chart-3: oklch(0.55 0.11 190); --chart-4: oklch(0.58 0.16 55); --chart-5: oklch(0.55 0.2 300); --chart-6: oklch(0.3 0 0); --chart-7: oklch(0.5 0 0); --chart-8: oklch(0.4 0 0); /* Sidebar. */ --sidebar: oklch(0.976 0 0); --sidebar-foreground: oklch(0.4 0 0); --sidebar-accent: oklch(0.92 0 0); --sidebar-accent-foreground: oklch(0.145 0 0); --sidebar-border: oklch(0.905 0 0);}.dark { /* Planes. */ --background: oklch(0.145 0 0); --surface: oklch(0.185 0 0); --card: oklch(0.205 0 0); --popover: oklch(0.24 0 0); --muted: oklch(0.269 0 0); --secondary: oklch(0.269 0 0); --accent: oklch(0.269 0 0); /* Ink. */ --foreground: oklch(0.985 0 0); --card-foreground: oklch(0.985 0 0); --popover-foreground: oklch(0.985 0 0); --muted-foreground: oklch(0.71 0 0); --faint-foreground: oklch(0.72 0 0); --secondary-foreground: oklch(0.985 0 0); --accent-foreground: oklch(0.985 0 0); /* The accent. */ --brand: oklch(0.985 0 0); --brand-foreground: oklch(0.205 0 0); --brand-muted: oklch(0.3 0 0); /* Lines. */ --border: oklch(0.27 0 0); --rule: oklch(0.36 0 0); --input: oklch(0.6 0 0); --chart-grid: oklch(0.29 0 0); /* Charts. */ --chart-1: oklch(0.75 0 0); --chart-2: oklch(0.68 0.16 258); --chart-3: oklch(0.72 0.12 190); --chart-4: oklch(0.75 0.15 60); --chart-5: oklch(0.7 0.17 300); --chart-6: oklch(0.88 0 0); --chart-7: oklch(0.6 0 0); --chart-8: oklch(0.54 0 0); /* Sidebar. */ --sidebar: oklch(0.205 0 0); --sidebar-foreground: oklch(0.8 0 0); --sidebar-accent: oklch(0.269 0 0); --sidebar-accent-foreground: oklch(0.985 0 0); --sidebar-border: oklch(0.27 0 0);}Or start from a palette
22 finished themes ship beside Vibra’s own, each one attribute on any wrapper, each held to the same contrast floors this page measures.