Skip to content

Tailwind CSS v4 theme() Function — Referencing Design Tokens

DodaTech Updated 2026-06-28 4 min read

In this tutorial, you will learn about Tailwind CSS v4 theme() Function. We cover key concepts, practical examples, and best practices to help you master this topic.

The Tailwind CSS v4 theme() function lets you reference @theme design tokens directly in custom CSS, bridging the gap between Tailwind utilities and hand-written style rules.

What You'll Learn

You will learn how to use theme() to access colors, spacing, fonts, and other tokens in custom CSS, combine theme() with calc(), and use it in @media and @container queries.

Why It Matters

theme() ensures consistency between Tailwind utilities and hand-written CSS. DodaTech uses theme() in component @layer rules and animation keyframes to maintain token alignment.

Real-World Use

DodaZIP's custom scrollbar styles use theme() to reference spacing and color tokens, ensuring the scrollbar matches the Tailwind-themed design without hardcoding values.

flowchart LR
    A[CSS-First Config] --> B[theme() Function]
    B --> C[Token Access]
    B --> D[calc() Math]
    B --> E[Keyframes]
    B --> F[Custom CSS]
    style B fill:#38bdf8,stroke:#0284c7,color:#fff
    style C fill:#22c55e,stroke:#16a34a,color:#fff

Basic theme() Usage

@import "tailwindcss";

@theme {
  --color-brand-500: #7c3aed;
  --spacing-4: 1rem;
  --font-family-sans: "Inter", sans-serif;
}

/* Using theme() in custom CSS */
.custom-element {
  background-color: theme(--color-brand-500);
  padding: theme(--spacing-4);
  font-family: theme(--font-family-sans);
}

Expected output: The custom element uses the same design tokens as Tailwind utilities. If the brand color changes in @theme, both Tailwind utilities and custom CSS update.

theme() with calc()

@theme {
  --spacing-nav: 4rem;
  --spacing-sidebar: 16rem;
}

/* Sidebar offset for main content */
.main-content {
  margin-left: theme(--spacing-sidebar);
  min-height: calc(100vh - theme(--spacing-nav));
}

/* Combined calculations */
.offset-box {
  padding: calc(theme(--spacing-4) * 2);
  margin-top: calc(theme(--spacing-nav) + theme(--spacing-4));
}

Expected output: theme() values work inside calc() for mathematical operations. Token changes propagate to calculated values.

theme() in Media Queries

@theme {
  --breakpoint-md: 48rem;
  --breakpoint-lg: 64rem;
  --spacing-4: 1rem;
  --spacing-8: 2rem;
}

@media (min-width: theme(--breakpoint-md)) {
  .responsive-card {
    padding: theme(--spacing-8);
    display: grid;
    grid-template-columns: 1fr 1fr;
  }
}

@media (min-width: theme(--breakpoint-lg)) {
  .responsive-card {
    grid-template-columns: 1fr 1fr 1fr;
  }
}

Expected output: Media queries use the same breakpoint tokens as Tailwind's responsive prefixes. Changing --breakpoint-md updates both @media queries and md: prefix.

theme() in @keyframes

@theme {
  --color-brand-500: #7c3aed;
  --color-brand-200: #ddd6fe;
  --spacing-4: 1rem;
}

@keyframes pulse-brand {
  0%, 100% {
    box-shadow: 0 0 0 0 theme(--color-brand-500);
  }
  50% {
    box-shadow: 0 0 0 theme(--spacing-4) theme(--color-brand-200);
  }
}

.pulse-button {
  animation: pulse-brand 2s infinite;
  background-color: theme(--color-brand-500);
  color: white;
  padding: theme(--spacing-4);
}

Expected output: Keyframes use theme() for colors and spacing. When the brand palette changes, animations update automatically.

theme() with Opacity

@theme {
  --color-brand-500: rgb(124 58 237 / 1);
}

/* theme() with opacity */
.faded-bg {
  background-color: rgb(from theme(--color-brand-500) r g b / 0.5);
}

/* Or using the / syntax if defined properly */
```css
@theme {
  --color-brand-500: rgb(var(--color-brand-500-rgb) / <alpha-value>);
}
:root {
  --color-brand-500-rgb: 124 58 237;
}

.faded-bg {
  background-color: rgb(from theme(--color-brand-500) r g b / 0.5);
}

Expected output: theme() can access token values and modify their opacity for custom usage.

Common Mistakes

1. Using theme() Without Dash Prefix

theme(color-brand-500) is incorrect. The dash prefix is required: theme(--color-brand-500).

2. Forgetting Parentheses in calc()

calc(100vh - theme(--spacing-nav)) is correct. calc(100vh - theme(--spacing-nav)) without the inner parentheses around the subtraction fails.

3. Using theme() in Static CSS Files

theme() only works in CSS files processed by Tailwind v4. Static CSS files without @import "tailwindcss" cannot resolve theme().

4. theme() with CSS Variables That Have Spaces

Theme values with spaces (like font-family lists) must be handled carefully: use quotes or handle as separate tokens.

5. Nesting theme() Calls

theme(--spacing-4) works. theme(theme(--custom-var)) does not. theme() does not support nesting.

Practice Questions

  1. What does theme() do in v4? References @theme design tokens in custom CSS, returning the token value.

  2. How do you use theme() with calc? calc(100% - theme(--spacing-4)) -- theme() provides the token value for the calculation.

  3. Can you use theme() in @media queries? Yes: @media (min-width: theme(--breakpoint-md)) uses the same breakpoint tokens.

  4. What happens when a @theme token changes? All theme() references automatically update on rebuild, keeping custom CSS in sync.

  5. Can theme() be used with any CSS property? Yes. theme() returns the raw token value, usable in any CSS property or function.

Challenge

Create a custom CSS file that uses theme() for: a sticky header with dynamic height, responsive @media queries based on token breakpoints, a keyframe animation using brand colors, and calc() combined with spacing tokens.

FAQ

Is theme() available in Tailwind v3?

v3 has a similar theme() for use in tailwind.config.js. v4's theme() is CSS-native and works in any processed CSS file.

Can theme() access nested object tokens?

v4 uses flat CSS variable names. Use theme(--color-brand-500) not theme(colors.brand.500).

Does theme() work in @apply?

Yes. @apply bg-[theme(--color-brand-500)] uses theme() inside arbitrary values.

Can I use theme() with CSS logical properties?

Yes: padding-inline: theme(--spacing-4) works with theme() references.

What happens if a theme token does not exist?

The CSS falls back to the raw text. No compile error, but the property is invalid and ignored.

Mini Project

Create a component library stylesheet that uses theme() throughout: button styles with brand colors, card spacing from tokens, responsive breakpoints from @theme, and keyframe animations referencing theme colors.

What's Next

Now master Variants in v4 for the unified variant system. Then explore Composing Variants for complex state combinations.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro