Skip to Content
FrontendRecipesTailwind v4

Tailwind v4

All django-cfg apps use Tailwind CSS v4 with CSS-first configuration.

For the full UI component library see UI Components.

Migration from v3

Import Syntax

v4 uses @import instead of @tailwind directives:

/* globals.css — v4 */ @import './theme.css'; /* Custom properties first */ @import 'tailwindcss'; /* NOT @tailwind directives */

Theme variables must come before the Tailwind import.

CSS-First Config

Theme configuration uses @theme {} blocks with CSS custom properties instead of tailwind.config.js:

@theme { --color-primary: hsl(222.2 47.4% 11.2%); --color-background: hsl(0 0% 100%); --color-destructive: hsl(0 84.2% 60.2%); --radius-lg: 0.5rem; --radius-md: calc(var(--radius-lg) - 2px); --radius-sm: calc(var(--radius-lg) - 4px); }

Opacity Modifiers

bg-background/80 works with the ui-core token system. Tokens are wired via @theme inline { --color-background: var(--background); }, so the opacity modifier resolves through color-mix(in oklab, …).

// ✅ Opacity modifiers work for every semantic token <div className="bg-background/80" /> <div className="border-border/30" /> <div className="bg-card/40 text-foreground/60" /> // ❌ Do NOT wrap tokens in hsl(var(--X)) — they are already full hsl(...) // colors, so this double-wraps to hsl(hsl(...)) and falls back to default. <div style={{ backgroundColor: 'hsl(var(--background) / 0.8)' }} />

If you need opacity in an inline style or arbitrary value, use color-mix over the variable (the variable already holds a complete color):

<div className="bg-[color-mix(in_oklab,var(--primary)_30%,transparent)]" />

This replaces the old v4 advice to use inline hsl(var(--X) / α) workarounds — that was needed before tokens moved to the @theme inline shape and is now incorrect. See @djangocfg/ui-core styles README → Token format.

Arbitrary Values

Arbitrary values like h-[80px] may not work reliably in v4. Define tokens in @theme or use inline styles:

/* In @theme block */ @theme { --spacing-header: 80px; --spacing-sidebar: 280px; }
// Use the token <div className="h-[--spacing-header]" /> // Or use inline style <div style={{ width: '80px', height: '80px' }} />

Breakpoints

Mobile-first breakpoints are unchanged from v3:

BreakpointMin Width
sm:640px
md:768px
lg:1024px
xl:1280px
2xl:1536px

DjangoCFG Preset

@djangocfg/ui-core provides a shared theme preset that all apps extend. The preset defines color tokens, border radii, font sizes, and animation timings that components depend on.

Rules

  1. Use @import 'tailwindcss' — never @tailwind base/components/utilities directives
  2. Import theme.css before tailwindcss in globals.css — order matters
  3. Use the opacity modifier (bg-card/40) for translucency — it works via @theme inline + color-mix; never wrap tokens as hsl(var(--X))
  4. Define reusable spacing and size values as tokens in @theme {} instead of using arbitrary values
  5. Keep breakpoints mobile-first — all utility classes apply from the specified breakpoint and up
Last updated on