Skip to content
UT Studio

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.

app/globals.css
@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 ofUseBecause
bg-whitebg-surfaceDark theme flips the value, not the markup
text-gray-500text-foreground-mutedContrast is guaranteed against its own background
border-gray-200border-borderOne 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.

Read next