---
title: "Tailwind"
slug: theming-tailwind
section: theming
order: 30
level: intermediate
description: "How to compose Tailwind v4 brand aliases that resolve through djust's runtime tokens, so utility classes recolor at runtime when packs swap."
---

# Tailwind

Tailwind v4's `@theme` block is for build-time tokens. djust's tokens
live at runtime and change per request. This page shows the **brand-alias
pattern** — how to declare Tailwind tokens that resolve through djust's
runtime variables, so `bg-brand-rust` is generated at build time but its
*value* still flows from whichever pack is active when the page loads.

## The pattern

```css
/* static/css/input.css */
@import "tailwindcss";
@plugin "@tailwindcss/typography";

@theme {
    --font-sans: 'Inter', ui-sans-serif, system-ui, sans-serif;
    --font-mono: 'JetBrains Mono', ui-monospace, Menlo, monospace;

    /* Brand aliases — Tailwind generates utilities at compile time;
     * the value resolves through djust's runtime CSS variable, so
     * swapping the active pack repaints the site without rebuilding
     * Tailwind. */
    --color-brand-dark:   hsl(var(--background));
    --color-brand-panel:  hsl(var(--card));
    --color-brand-rust:   hsl(var(--primary));
    --color-brand-text:   hsl(var(--foreground));
    --color-brand-muted:  hsl(var(--muted-foreground));
    --color-brand-border: hsl(var(--border));
}

@source "../../templates";
@source "../../docs_app";
```

After `make tailwind-build`, you can use:

```html
<button class="bg-brand-rust text-brand-text hover:bg-brand-rust/80">
    Read the docs
</button>
```

The class names are static (Tailwind sees them at build time and emits
the rules). The colors are dynamic (the rules reference the runtime
`--background` etc., which swap per request).

## Why two layers?

Tailwind v4 generates utilities from `@theme` declarations. If you fed
the runtime `var(--background)` directly into `@theme`, Tailwind would
freeze its value at build time and you'd lose the runtime swap.

The brand aliases are an indirection — they live at build time (so
Tailwind can generate utilities) but they *contain* runtime references
(so the actual paint color is dynamic).

## Naming conventions

Two reasonable strategies:

### 1. Mirror djust's vocabulary

```css
--color-primary:           hsl(var(--primary));
--color-primary-foreground: hsl(var(--primary-foreground));
--color-card:              hsl(var(--card));
```

Pro: zero translation cost.
Con: Tailwind already has `text-primary` semantics; collisions are easy.

### 2. Use a brand prefix

```css
--color-brand-dark:   hsl(var(--background));
--color-brand-rust:   hsl(var(--primary));
--color-brand-text:   hsl(var(--foreground));
--color-brand-muted:  hsl(var(--muted-foreground));
--color-brand-border: hsl(var(--border));
```

Pro: no Tailwind collisions, easy to grep, semantic at a glance.
Con: an extra layer of name to maintain.

This is the docs.djust.org convention and what most shipped sites use.

## Opacity composition

Tailwind's `/N` opacity modifier works through the alias because the
runtime variable is the HSL triplet:

```html
<div class="bg-brand-rust/20"></div>     <!-- 20% opacity rust -->
<div class="border-brand-border/40"></div>
```

Internally Tailwind generates `background: hsl(var(--primary) / 0.2)`,
which composes with djust's HSL-triplet convention.

## What about `@apply`?

Avoid `@apply` for brand utilities — they bake in the build-time alias,
which still respects runtime swaps but adds an indirection that makes
later debugging harder. Inline the utility classes on the elements
instead, or write plain CSS that uses `var(--...)` directly.

## What about other CSS frameworks?

Bootstrap users follow the same pattern via Sass variables. djust ships
a `bootstrap-bridge.css` that maps shadcn tokens to Bootstrap variables;
see [CSS Frameworks](/guides/css-frameworks/).

## See also

- **[Tokens](/theming/tokens/)** — what each `--background`,
  `--primary`, `--foreground` actually paints.
- **[CSS Frameworks](/theming/css-framework/)** — the broader
  framework-abstraction story (Bootstrap 4 / 5, Tailwind, plain) plus
  the Bootstrap bridge that does for `.btn-primary` what brand aliases
  do for Tailwind.
- **[CSS Frameworks (setup guide)](/guides/css-frameworks/)** — full
  Tailwind / Bootstrap installation guide with djust.
- **[Recipes](/theming/recipes/)** — patterns for overriding tokens
  per-page or per-section without a new pack.
