---
title: "CSS Variables"
slug: theming-tokens
section: theming
order: 20
level: beginner
description: "Every CSS variable djust emits — the shadcn-style base set, the djust extensions, and the surface levels. Each one painted, with examples."
---

# CSS Variables

Every theme pack emits a runtime `<style>` block of CSS custom properties
into your document. Tailwind utilities, your own CSS, and djust's
shipped components all resolve through those variables — so swapping
packs at runtime recolors the entire site without a rebuild.

The naming follows shadcn/ui conventions, with djust extensions for
states (`success`, `warning`, `info`), media (`link`, `code`,
`selection`), and structural surfaces (`surface_1` / `_2` / `_3`).

## The HSL triplet convention

Every color token is emitted as an **HSL triplet** with no `hsl(...)`
wrapper:

```css
--background: 40 30% 7%;        /* not hsl(40 30% 7%) */
--primary: 28 85% 55%;
```

You wrap with `hsl(...)` at the consumption site. The win: opacity
composes naturally:

```css
background: hsl(var(--primary));
border: 1px solid hsl(var(--primary) / 0.5);    /* 50% opacity */
box-shadow: 0 0 0 4px hsl(var(--ring) / 0.2);
```

## The full token list

### Base surfaces

| Token | What it paints |
|---|---|
| `--background` | The page background. |
| `--foreground` | Body text on `--background`. |
| `--card` | Slightly lifted surface (cards, panels, modals). |
| `--card-foreground` | Text inside a card. |
| `--popover` | Popover / dropdown / tooltip background. |
| `--popover-foreground` | Text inside a popover. |

### Action

| Token | What it paints |
|---|---|
| `--primary` | The dominant action color (CTA buttons, focused inputs, link). |
| `--primary-foreground` | Text on a `--primary` background. |
| `--secondary` | Subdued action (cancel buttons, alternate fills). |
| `--secondary-foreground` | Text on `--secondary`. |
| `--accent` | Highlights (active nav, selected row). Often equals `--primary`. |
| `--accent-foreground` | Text on `--accent`. |
| `--muted` | Muted background (disabled fills, subtle dividers). |
| `--muted-foreground` | Subdued text — captions, secondary labels. |
| `--destructive` | Red for delete confirms, error states. |
| `--destructive-foreground` | Text on `--destructive`. |

### Status (djust extensions)

| Token | What it paints |
|---|---|
| `--success` | Green for confirmations, success toasts. |
| `--success-foreground` | Text on `--success`. |
| `--warning` | Amber/orange for warnings. |
| `--warning-foreground` | Text on `--warning`. |
| `--info` | Blue for informational callouts. |
| `--info-foreground` | Text on `--info`. |

### Media (djust extensions)

| Token | What it paints |
|---|---|
| `--link` | Inline link color. |
| `--link-hover` | Link color on hover. |
| `--code` | `<code>` background tint. |
| `--code-foreground` | `<code>` text color. |
| `--selection` | `::selection` background. |
| `--selection-foreground` | `::selection` text. |
| `--brand` | Distinctive identity color, often *more* saturated than `--primary` (Dracula Pink, Nord Frost, Catppuccin Rosewater). Set to match `--primary` if your pack has no separate brand color. |
| `--brand-foreground` | Text on `--brand`. |

### UI elements

| Token | What it paints |
|---|---|
| `--border` | Default border color (cards, inputs, dividers). |
| `--input` | Input field border (often equals `--border`). |
| `--ring` | Focus ring (often equals `--primary`). |

### Surfaces (djust extensions for landing-page layering)

For complex dark layouts that need three distinct elevation levels:

| Token | What it paints |
|---|---|
| `--surface-1` | Darkest — ultra-dark base background. |
| `--surface-2` | Mid — panels, navbars. |
| `--surface-3` | Elevated — cards, modals. |

A simple light-mode pack can leave these all equal to `--background`
and `--card`. Dark editorial / dashboard packs typically use them to
build depth without shadows.

### Geometry

| Token | What it paints |
|---|---|
| `--radius` | Border-radius multiplier in `rem` (e.g. `--radius: 0.5rem`). Components like buttons and cards multiply this. |

## Light vs. dark

Every shipped pack defines a `LIGHT` and a `DARK` set of these tokens.
The active mode determines which set goes into `:root`. The mode-switcher
flips `:root` (or a `.dark` class, depending on pack config) and the
whole site recolors immediately — no JS needed for the recoloring
itself, only for storing the user's choice.

## Where to find the canonical list

Source of truth is the
[`ThemeTokens`](https://github.com/djust-org/djust/blob/main/python/djust/theming/_types.py)
dataclass. Every shipped pack populates the same field set — you can
copy the closest pack and tweak.

## See also

- **[Settings](/theming/settings/)** — how to choose which pack emits
  these tokens at request time.
- **[Tailwind](/theming/tailwind/)** — declaring brand aliases that
  resolve through these tokens.
- **[`extra_css_vars`](/theming/extra-css-vars/)** — for project-specific
  variables outside this token set.
