How the tokens are organised#
- Raw tokens are CSS custom properties named
--pixilui-*(for example--pixilui-surface,--pixilui-radius-control). The prefix keeps them apart from shadcn's--backgroundand--accent, which mean something else. - Utilities map the raw tokens into Tailwind v4 through
@theme inline. Items use only the utilities:bg-surface,text-secondary,border-border,rounded-control,h-control-md,text-14,shadow-raised,duration-fast.
| Group | Utilities |
|---|---|
| Surfaces | bg-background, bg-surface, bg-surface-raised, bg-surface-muted, bg-surface-inverted |
| Text | text-foreground, text-secondary, text-muted, text-inverted |
| Borders | border-border, border-border-subtle, border-border-strong, and hairline (a 1px overlay that never changes a measurement) |
| Accent | bg-accent-solid, text-accent-contrast, text-accent-strong, bg-accent-subtle |
| Status | bg-success, text-danger, bg-warning-subtle, text-info-foreground, and the same for each of success, warning, danger, info |
| Radii | rounded-control (18px), rounded-panel (26px), rounded-surface (34px), rounded-pill |
| Control heights | h-control-sm (36px), h-control-md (44px), h-control-lg (50px), also as w- and size- |
| Type | text-12, text-14, text-16, text-18, text-22, text-28, text-36, text-52, text-72, with line height and tracking included; font-display, font-body, font-mono |
| Shadows | shadow-resting, shadow-raised, shadow-floating |
| Motion | duration-instant to duration-spring, ease-enter, ease-smooth-out, ease-exit, ease-move, ease-swap |
Two names differ from the role names on purpose. The accent fill is bg-accent-solid and text on it is text-accent-contrast, because shadcn uses bg-accent and text-accent-foreground for the grey hover in its menus. pixilui leaves those alone, so your existing shadcn components keep their look.
The type scale (text-12 to text-72) is separate from Tailwind's text-sm and text-xl, so installing pixilui never shifts your typography.
Dark mode#
Light is the default. Dark applies under [data-theme="dark"] or the .dark class, on <html> or on any element:
<html data-theme="dark"><html class="dark">The .dark class is what next-themes and shadcn apps already set, so pixilui follows your existing toggle. There is no prefers-color-scheme default: your app decides. Dark values are tuned separately, not inverted: surfaces step up in lightness as they rise, and text roles keep 4.5:1 contrast on their surfaces.
Because the theme is read where it is used, you can nest themes. A dark preview inside a light page, or a light card inside a dark sidebar, renders correctly:
<div data-theme="dark">
<ApprovalCard {...props} />
</div>Approved
Approved
Accents#
Eight accents ship with the foundation. Set one with data-accent on any element; without it the accent is neutral (near black in light, near white in dark). Pick a row to try it on the button.
| Accent | Light fill | Dark fill |
|---|---|---|
neutral |
oklch(0.2 0 0) |
oklch(0.94 0 0) |
violet |
oklch(0.54 0.21 290) |
oklch(0.56 0.2 290) |
blue |
oklch(0.56 0.225 263) |
oklch(0.56 0.2 263) |
green |
oklch(0.53 0.13 155) |
oklch(0.72 0.15 155) |
amber |
oklch(0.8 0.16 78), dark text |
oklch(0.82 0.15 80), dark text |
orange |
oklch(0.56 0.17 42) |
oklch(0.72 0.16 48), dark text |
coral |
oklch(0.56 0.17 28) |
oklch(0.72 0.15 30), dark text |
rose |
oklch(0.55 0.2 8) |
oklch(0.56 0.2 8) |
<body data-accent="violet">Each accent has four roles: the fill (bg-accent-solid, used by primary buttons, selection and switches), text on the fill (text-accent-contrast), accent-coloured text and icons (text-accent-strong), and a tinted background (bg-accent-subtle). Light fills stay dark enough for white text to clear 4.5:1; amber and the lighter dark fills switch to dark text instead.
The accent is also the focus colour: focus-visible:focus-ring draws a 2px outline in the accent with a 2px offset.
Overriding roles#
To change a role everywhere, override its raw token after the foundation import. Set light values on :root and dark values under your dark selector:
:root {
--pixilui-background: oklch(0.985 0.004 90);
--pixilui-radius-control: 12px;
--pixilui-radius-panel: 18px;
--pixilui-radius-surface: 24px;
}
[data-theme="dark"],
.dark {
--pixilui-background: oklch(0.15 0.004 90);
}Keep the radii nested (control smaller than panel, panel smaller than surface), so a control inside a panel inside a surface still looks concentric.
To use your brand colour as the accent, set --pixilui-accent and its three partners. These win over data-accent in both themes:
:root {
--pixilui-accent: oklch(0.55 0.2 145);
--pixilui-accent-strong: oklch(0.48 0.18 145);
--pixilui-accent-subtle: oklch(0.96 0.03 145);
--pixilui-accent-foreground: oklch(0.99 0 0);
}To keep separate light and dark brand values, override the pairs instead (--pixilui-accent-light, --pixilui-accent-dark, and the same for -strong, -subtle and -foreground), and the theme in force picks one.
Restyling one item#
Items expose their state as data attributes (data-status, data-loading, data-risk), and every item takes className, merged last. Target the attributes from your own CSS or with Tailwind's data-* variants instead of editing the item:
<ApprovalCard className="data-[risk=high]:shadow-floating" {...props} />