Theming
Every design decision lives in one stylesheet, @viliha/vui-react/theme.css, as a CSS variable. Change the tokens and the whole system follows.
Token groups
- Surfaces & text:
--background,--foreground,--card,--popover,--muted,--accent. - Actions:
--primary,--destructive, and the brand--button-primary/--button-primary-hover/--button-shadow. - Lines & focus:
--border,--input,--ring. - Sidebar, charts, radius, selection:
--sidebar-*,--chart-1..5,--radius,--selection.
Color system
These are the semantic colors you reach for most. Every component reads them, so changing a single token restyles the whole system. Each pairs with a matching -foreground for the text that sits on top.
| Color | Token | Value | Usage |
|---|---|---|---|
| Primary (action) | --button-primary | #266DF0 | Primary buttons, active states, links |
| Primary hover | --button-primary-hover | #215BC4 | Hover state of the primary action |
| Foreground | --foreground | #101112 | Default text color |
| Primary (neutral) | --primary | oklch(0.205 0 0) | Neutral solid button / emphasis |
| Secondary | --secondary | oklch(0.97 0 0) | Secondary button / subtle fills |
| Hover surface | --accent | oklch(0.97 0 0) | Hover background on rows, items, ghost buttons |
| Muted | --muted | oklch(0.97 0 0) | Section header bg, muted text on -foreground |
| Destructive | --destructive | oklch(0.577 0.245 27) | Delete / error states |
| Success | --success | #039855 | Confirmations, healthy status, positive deltas |
| Warning | --warning | #dc6803 | Needs attention, but nothing has failed |
| Info | --info | #0086c9 | Neutral notices and hints |
| Border | --border | oklch(0.922 0 0) | All borders and dividers |
| Ring | --ring | oklch(0.708 0 0) | Focus ring |
| Selection | --selection | #266DF0 | Text selection highlight |
💡 Four state colours, and all four are yours
--destructive, --success, --warning and --info are the whole state family, in light and dark. Nothing in the components reaches past them to a fixed palette colour, so overriding these four moves every badge, alert, status dot and delta arrow in the product at once. There is a test that goes red if a palette class comes back.Primary: neutral vs. action
shadcn's
--primary is the neutral, near-black solid the default button uses. The brand action color is a separate token, --button-primary (#266DF0), paired with --button-primary-hover for its hover state. It drives <Button variant="primary">, checkboxes, and active states, while hover surfaces (rows, items, ghost buttons) fall back to --accent.Default tokens
theme.css (excerpt)
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.177 0 0); /* #101112 */
--primary: oklch(0.205 0 0);
--radius: 0.625rem;
--selection: #266df0;
--button-primary: #266df0; /* brand primary button */
/* …neutral palette, chart + sidebar tokens… */
}How do I rebrand the theme?
Override tokens after importing the theme:
app/globals.css
@import "tailwindcss";
@import "@viliha/vui-react/theme.css";
:root {
--primary: oklch(0.55 0.2 260); /* your brand */
--radius: 0.5rem;
}How does dark mode work?
The tokens ship with a .dark block. Add the dark class to <html> to switch, and wire that class to a theme toggle or the OS preference.
<html class="dark">Typography
The baseline is Inter at 14px medium in
#101112. To match the demo, supply the --font-inter and --font-jetbrains-mono CSS variables, for example through next/font.