Themes
A theme in PresetUI is a list of colour values — nothing more. There is no theme provider, no config file, and no JavaScript involved. Every component reads the same tokens, so replacing the values replaces the look of the whole kit.
Palettes
Click a palette to apply it to this page. The docs chrome changes too, because the site is built from the same components you'd be copying.
click a palette to apply it
The two tiers
Core tokens are required. Every component reads them, and a missing one breaks that component everywhere.
| Token | Used for |
|---|---|
--color-surface | Page and component backgrounds |
--color-fg | Primary text |
--color-muted | Secondary text, placeholders, icons |
--color-border | Borders, dividers, subtle fills |
--color-accent | Primary buttons, selected states, focus rings |
--color-accent-fg | Text on top of accent |
--color-danger | Destructive actions and error states |
Optional tokens power specific variants. They ship in the theme file, but you can delete them if you don't use the variants that need them.
| Token | Needed by |
|---|---|
--color-success | Alert and Badge, variant="success" |
--color-warning | Alert and Badge, variant="warning" |
If you delete an optional token and use its variant anyway, the background renders empty. Tailwind can't generate a utility for a token that doesn't exist, and it fails quietly rather than erroring.
Dark mode
Dark mode is not a second set of tokens — it is the same names with different
values, applied under a dark class on <html>:
@theme {
--color-surface: #ffffff;
--color-fg: #0a0a0a;
}
.dark {
--color-surface: #0a0a0a;
--color-fg: #fafafa;
}That is why no component contains a single dark: utility. They don't know
which mode they're in, and they don't need to.
Adding your own token
Define it alongside the others, then use it in a component like any Tailwind colour:
@theme {
--color-brand: #6d28d9;
--color-brand-fg: #ffffff;
}<button className="bg-brand text-brand-fg">Upgrade</button>Remember to add the value under .dark too, or your token will keep its light
value when the rest of the page goes dark.
Building a palette that holds up
The kit's contrast comes from the relationship between the tokens, not from any single value:
fgonsurfacecarries all your body text — keep it at 7:1 or better.mutedonsurfaceis used for secondary text at small sizes. 4.5:1 is the floor, and it is the pair most often got wrong.accent-fgonaccentsits inside buttons. If you pick a mid-tone accent, check this pair specifically — it fails more often than it looks like it will.bordershould be visible againstsurfacewithout competing withfg.dangerneeds to work as a background (with white text, as Badge uses it) and as a border and tint (as Alert uses it).