--- name: tailwind-v4-idioms description: TailwindCSS v4 (4.3.3 as of 2026-07) — CSS-first config, no tailwind.config.js by default, container queries, custom variants. when_to_use: You're authoring styles in a TailwindCSS v4 project. Frontend team pins this. tags: [frontend, css, tailwind, versioned] --- # TailwindCSS v4 (4.3.3) ## What changed vs v3 - **CSS-first config**. No `tailwind.config.js` by default. Theme tokens live in your CSS via `@theme { ... }`. - **`@import "tailwindcss"`** replaces the three `@tailwind base/components/utilities` directives. - **Zero-config content detection** — scans automatically via the Vite/PostCSS plugin, no `content: [...]` glob. - **Native CSS variables everywhere** — every design token is a `--color-primary` style var, usable in raw CSS. - **Container queries built-in** — `@container/name` variant, no plugin. - **Faster** — Rust-powered engine (Oxide), ~100× faster incremental builds. ## Minimal setup ```css /* app.css */ @import "tailwindcss"; @theme { --color-brand-500: oklch(0.7 0.15 250); --font-display: "Inter", ui-sans-serif; } ``` Then in a component: `class="text-brand-500 font-display"`. ## Class-order convention For each `class="..."` attribute, order tokens: ``` [layout] → [box] → [typography] → [color] → [state] flex items-center gap-2 → w-full p-4 rounded-lg → text-sm font-semibold → text-white bg-brand-500 → hover:bg-brand-600 focus:outline-none ``` Prettier's `prettier-plugin-tailwindcss` enforces this — run it in CI. ## Design system integration (ShadCN) - ShadCN 2.x ships v4-native components. No compat layer needed. - Custom variants: define once in `@variant` and reuse: ```css @variant hocus (&:hover, &:focus-visible); /* class="hocus:bg-brand-500" */ ``` - Prefer `data-[state=open]:...` variants for stateful ShadCN primitives. ## Container queries ```html

Adapts to card width, not viewport.

``` - Name the container (`/card`) so nested containers don't cross-reference. - Breakpoints: `@sm`, `@md`, `@lg`, `@xl` follow the same px values as viewport. ## Dark mode `@media (prefers-color-scheme: dark)` is picked up automatically. For a manual toggle, use `dark:` variant + a class or attribute switch on `` (`data-theme="dark"` + `@variant dark (&[data-theme="dark"] *)`). ## Anti-patterns - **Bringing back `tailwind.config.js`** for one tweak. Use `@theme` in CSS instead. - **Inline styles alongside utility classes** — pick one per element. - **`@apply` in component CSS** — allowed but should be rare; utility class in JSX is usually clearer. - **Arbitrary values everywhere** — `class="mt-[13px]"` is a code smell if it repeats. Promote to a theme token.