Tailwind CSS in these templates
How the token layer, theme switching and utility conventions fit together.
UT Studio6 min read
Templates use Tailwind CSS v4, configured in CSS rather than in a JavaScript config file. If you are coming from v3, that is the largest single difference and the one worth reading about before you start editing.
Tokens are CSS variables
Every design decision is a custom property defined in one place, and every utility resolves to one. There is no `tailwind.config.js` holding a second copy of the palette.
@import "tailwindcss";
@theme {
--color-surface: oklch(1 0 0);
--color-foreground: oklch(0.15 0.01 260);
--radius-panel: 0.75rem;
}Semantic names, not colour names
Tokens are named for what they mean — `surface`, `foreground-muted`, `border-strong` — rather than for what colour they currently are. A token called `blue-500` becomes a lie the moment the brand changes; `primary` never does. It is also what makes a dark theme a set of new values rather than a set of new classes.
| Instead of | Use | Because |
|---|---|---|
| bg-white | bg-surface | Dark theme flips the value, not the markup |
| text-gray-500 | text-foreground-muted | Contrast is guaranteed against its own background |
| border-gray-200 | border-border | One border colour, changed once |
How theming works
Light is the base. Dark is the same token names redefined under a `prefers-color-scheme` media query and again under an explicit `[data-theme="dark"]` selector, so an OS preference and a user override both work — and the override wins in both directions.
Never define a colour only inside a media query
A token that exists only in the dark block is undefined in light, and the component using it falls back to whatever it inherits. Define every token in the base, then redefine it.
Utility conventions
- Layout and spacing go on the element. Repeating a spacing value is fine; extracting a class for it is usually not.
- Repeated visual treatments become a component, not an `@apply` rule. `@apply` recreates the stylesheet problem Tailwind exists to avoid.
- Arbitrary values are a signal. One is fine; a file full of them means a missing token.
Templates mentioned here
Everything above is written against real products. These are the ones this page draws on.
