Capítulo 13 de 29

Chapter 13: Theme Variables

Core Idea

@theme defines design tokens as special CSS custom properties that Tailwind reads to generate matching utility classes and variants — unlike plain :root variables, a theme variable is both a normal CSS variable and an instruction to create a utility/variant with the same name, which is why it needs its own directive and must live at the top level (never nested).

Key Concepts

  • @theme vs :root: use @theme when a value should generate a utility class; use :root for a variable that's just a variable with no corresponding utility.
  • Namespace → utility/variant mapping (defining a token in a namespace makes the matching class/variant available):
NamespaceDrives
--color-*Color utilities (bg-red-500, text-sky-300, ...)
--font-*Font family (font-sans)
--text-*Font size (text-xl)
--font-weight-*Font weight (font-bold)
--tracking-*Letter spacing (tracking-wide)
--leading-*Line height (leading-tight)
--tab-size-*Tab size (tab-github)
--breakpoint-*Responsive variants (sm:*)
--container-*Container query variants (@sm:*) and size utilities (max-w-md)
--spacing-* / --spacingSpacing/sizing utilities (px-4, max-h-16, ...)
--radius-*Border radius (rounded-sm)
--shadow-* / --inset-shadow-*Box shadow / inset shadow
--drop-shadow-*Drop-shadow filter
--blur-*Blur filter
--perspective-*Perspective
--zoom-*Zoom
--aspect-*Aspect ratio
--ease-*Transition timing function
--animate-*Animation (paired with a @keyframes block)
  • Static utilities are separate: some classes (flex, object-cover) are hardcoded, not theme-driven — only namespaced tokens generate/remove utilities dynamically.
  • Default theme: @import "tailwindcss" pulls in theme.css (default palette, type scale, shadows, fonts) as the theme layer, alongside preflight.css (base) and utilities.css (utilities) — everything like bg-red-200/font-serif/shadow-sm exists because the default theme defines those tokens, not because they're built into the framework.
  • Extending: add a new token (--font-script: "Great Vibes", cursive;) to get a new utility (font-script) alongside the defaults.
  • Overriding one value: redefine an existing token (--breakpoint-sm: 30rem;) to change that one utility/variant's behavior.
  • Overriding a whole namespace: --color-*: initial; then define only your replacements — removes every default utility in that namespace, keeping only your custom ones.
  • Fully custom theme: --*: initial; at the top of @theme wipes every default token across all namespaces — only tokens you define afterward produce utilities. Useful for a from-scratch design system.
  • Animation keyframes: define @keyframes inside @theme alongside the matching --animate-* token so the keyframes ship in the generated CSS; define them outside @theme instead if they should always be included regardless of whether the --animate-* utility is used.
  • @theme inline: required when a token's value references another CSS variable (--font-sans: var(--font-inter);). Without inline, the utility emits var(--font-sans) which resolves where --font-sans is defined (often the document root) — if the variable it points to (--font-inter) is only set deeper in the tree (e.g. by a font-loader script on a nested element), the outer reference sees no value and silently falls back. inline bakes in the value at compile time instead of leaving a live reference, avoiding that scoping trap.
  • @theme static: forces all theme variables to be emitted as CSS custom properties in the output, even ones no utility class currently uses — useful when you plan to reference var(--color-primary) directly (e.g. from JS or hand-written CSS) without ever using the matching utility class (which is what would normally trigger generation).
  • Sharing across projects: theme variables are just CSS, so a shared @theme { --*: initial; ... } block can live in its own file/package and be pulled into multiple projects via @import "../brand/theme.css"; — works for monorepo packages or an npm-published theme file.
  • Using theme values elsewhere: reference generated --token variables directly in custom CSS (color: var(--color-gray-700);), in arbitrary values combined with calc() (rounded-[calc(var(--radius-xl)-1px)]), or in JS — either pass the CSS variable straight through to an animation library (Motion: animate={{ backgroundColor: "var(--color-blue-500)" }}), or resolve it at runtime with getComputedStyle(document.documentElement).getPropertyValue("--shadow-xl").

Code Examples

@theme {
  --color-mint-500: oklch(0.72 0.11 178);   /* → bg-mint-500, text-mint-500, fill-mint-500, ... */
  --breakpoint-3xl: 120rem;                  /* → 3xl:* variant */
}
/* fully custom theme, no defaults survive */
@theme {
  --*: initial;
  --spacing: 4px;
  --font-body: Inter, sans-serif;
  --color-lagoon: oklch(0.72 0.11 221.19);
}
  • What it demonstrates: a single new color token generating a whole family of color utilities, a breakpoint token generating a variant, and wiping the default theme entirely to start from a bespoke token set.

Key Takeaways

  1. A theme token's namespace (the part before the last -*) determines what kind of utility/variant it produces — naming a token correctly is what wires it up, there's no separate registration step.
  2. Use @theme inline whenever a token's value is var(...) pointing at something set elsewhere in the cascade — plain @theme can silently produce a broken fallback in that case.
  3. --*: initial (global) and --namespace-*: initial (single namespace) are the only two ways to remove default tokens — there's no per-token deny-list.
  4. Prefer referencing generated --token CSS variables over hand-copying values (colors, shadows, spacing) into custom CSS or JS — it stays in sync automatically when the theme changes.

Connects To

  • Colors: the --color-* namespace is the same mechanism, covered there with the full default palette.
  • Adding Custom Styles: @theme alongside @utility/@custom-variant for the full custom-extension toolkit.
  • Responsive Design / Container Queries: --breakpoint-*/--container-* are theme namespaces that generate variants, not utilities.