web-styling-tailwind
Tailwind CSS v4 Patterns
Quick Guide: Tailwind CSS v4 uses CSS-first configuration with
@import "tailwindcss"and@themedirective (NOTtailwind.config.js). Define design tokens as CSS variables in@theme, create custom utilities with@utility, custom variants with@custom-variant. Automatic content detection (nocontentarray). Use@tailwindcss/viteplugin for Vite projects. All colors use oklch. No Sass/Less/Stylus support.
Detailed Resources:
- For code examples, see examples/ folder:
- core.md - Setup, responsive design, dark mode, state variants, theme customization
- advanced.md - Custom utilities, custom variants, container queries, 3D transforms, animations, component extraction
<critical_requirements>
⚠️ CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST use @import "tailwindcss" and @theme for configuration - NEVER use tailwind.config.js, @tailwind base, or module.exports)
(You MUST use @utility for custom utilities - NEVER use @layer utilities {} (v3 syntax))
(You MUST use oklch or CSS variable references for custom colors in @theme - NEVER use hex/rgb for theme tokens)
(You MUST use @tailwindcss/vite for Vite projects and @tailwindcss/postcss for others - NEVER use tailwindcss directly as PostCSS plugin)
(You MUST specify border colors explicitly - v4 defaults to currentColor not gray-200)
</critical_requirements>
Auto-detection: Tailwind CSS, tailwindcss, @import "tailwindcss", @theme, @utility, @custom-variant, utility classes, bg-, text-, flex, grid, responsive design, dark:, hover:, focus:, @tailwindcss/vite, @tailwindcss/postcss, tailwind-merge, cn()
When to use:
- Styling with utility-first CSS classes directly in markup
- Configuring design tokens with CSS-first
@themedirective - Implementing responsive design with breakpoint variants
- Adding dark mode with
dark:variant - Creating custom utilities and variants in CSS
- Building component libraries with Tailwind + React
- Using container queries, 3D transforms, or modern CSS features
Key patterns covered:
- CSS-first setup with
@import "tailwindcss"and@theme - Responsive design with breakpoint variants (
sm:,md:,lg:) - Dark mode configuration (media, class, data-attribute strategies)
- State variants (
hover:,focus:,group-*:,peer-*:) - Theme customization with
@themenamespaces - Custom utilities with
@utilityand functional values - Custom variants with
@custom-variant - Container queries (
@container,@sm:,@max-*:) - 3D transforms (
rotate-x-*,perspective-*,transform-3d) - Animation with
@starting-styleand@keyframes - Component extraction with
cn()(clsx + tailwind-merge) - Migration notes from v3 to v4
When NOT to use:
- Projects requiring Sass/Less/Stylus (v4 is a standalone preprocessor, no Sass support)
- Projects needing IE11 or older browser support (requires Safari 16.4+, Chrome 111+, Firefox 128+)
- Tiny projects where a full utility framework is overkill (use plain CSS)
- Projects already using SCSS Modules with an established design system
Philosophy
Tailwind CSS v4 follows a utility-first, CSS-native approach: style directly in markup using composable utility classes, configure design tokens in CSS with @theme, and extend with @utility/@custom-variant directives. No JavaScript configuration files needed.
Core Principles:
- Utility-first: Compose styles from small, single-purpose classes in HTML
- CSS-first configuration: Design tokens defined in CSS via
@theme, not JavaScript - Zero configuration defaults: Automatic content detection, sensible default theme
- Variant-driven states: Responsive, dark mode, hover, focus -- all via class prefixes
- Modern CSS foundation: Built on cascade layers,
@property,color-mix(), oklch colors - Performance-first: 5x faster full builds, 100x faster incremental rebuilds vs v3
v4 vs v3 -- Key Differences:
| Aspect | v3 | v4 |
|---|---|---|
| Config | tailwind.config.js |
@theme in CSS |
| Import | @tailwind base/components/utilities |
@import "tailwindcss" |
| Custom utilities | @layer utilities {} |
@utility name {} |
| Custom variants | addVariant() plugin |
@custom-variant |
| Content detection | Manual content: [] |
Automatic |
| Colors | sRGB hex/rgb | oklch (P3 gamut) |
| Border default | gray-200 |
currentColor |
| Ring default | 3px blue-500 |
1px currentColor |
| Important modifier | !flex |
flex! |
| Arbitrary vars | bg-[--var] |
bg-(--var) |
| Container queries | Plugin required | Built-in |
| 3D transforms | Not available | Built-in |
Core Patterns
Pattern 1: CSS-First Setup and Configuration
Tailwind v4 replaces JavaScript config with CSS-first configuration. Use @import "tailwindcss" instead of @tailwind directives, and @theme instead of tailwind.config.js.
Installation Options
Vite projects (recommended): Use @tailwindcss/vite for optimal performance.
Other bundlers: Use @tailwindcss/postcss as PostCSS plugin.
CLI: Use @tailwindcss/cli for standalone builds.
Key Concepts
@import "tailwindcss"replaces the three@tailwinddirectives@themedefines design tokens that generate utility classes AND CSS variables@sourceadds paths not caught by automatic content detection- No
contentarray needed -- Tailwind auto-detects template files respecting.gitignore
For implementation examples, see examples/core.md.
Pattern 2: Responsive Design with Breakpoint Variants
Tailwind v4 uses mobile-first responsive design with breakpoint variants. Default breakpoints: sm (40rem), md (48rem), lg (64rem), xl (80rem), 2xl (96rem).
Key Concepts
- Mobile-first: base styles apply to all, breakpoint variants add overrides
- Custom breakpoints defined in
@themewith--breakpoint-*namespace - Stack breakpoints for ranges:
md:max-lg:hidden(hide between md and lg) - Use
max-*variants for max-width queries:max-md:hidden
For implementation examples, see examples/core.md.
Pattern 3: Dark Mode
Tailwind v4 supports three dark mode strategies: media query (default), class-based toggle, and data-attribute toggle. Override the dark variant with @custom-variant.
Strategies
- Media query (default): Uses
prefers-color-scheme: dark-- zero config - Class-based: Add
.darkclass to<html>-- use@custom-variant dark - Data-attribute: Use
data-theme="dark"-- use@custom-variant dark
Key Concepts
- Default dark mode works with system preference, no config needed
- For manual toggle, override the
darkvariant with@custom-variant - Use
(&:where(.dark, .dark *))selector for class strategy - Theme variables in
@themecan reference CSS variables set by theme class
For implementation examples, see examples/core.md.
Pattern 4: State Variants
Tailwind v4 provides comprehensive state variants for interactive styling. The not-* variant is new in v4.
Available Variants
- Pseudo-classes:
hover:,focus:,active:,visited:,first:,last:,odd:,even:,disabled:,required:,invalid: - Group/Peer:
group-hover:,group-focus:,peer-checked:,peer-invalid: - Data attributes:
data-[state=active]:,data-current: - New in v4:
not-hover:,not-focus:,inert:,starting:(for@starting-style) - Container queries:
@sm:,@md:,@lg:,@max-sm:
Key v4 Changes
hover:only applies on devices with hover capability (no more mobile ghost hovers)not-*variant styles when condition is NOT met- Variant stacking is left-to-right (CSS order):
dark:hover:bg-gray-700
For implementation examples, see examples/core.md.
Pattern 5: Theme Customization with @theme
The @theme directive defines design tokens that generate both utility classes and CSS variables. Each namespace maps to specific utility types.
Namespaces
| Namespace | Generates | Example |
|---|---|---|
--color-* |
Color utilities | bg-brand-500, text-brand-500 |
--font-* |
Font family | font-display |
--text-* |
Font size | text-display |
--spacing-* |
Spacing | px-compact |
--breakpoint-* |
Responsive variants | 3xl:flex |
--radius-* |
Border radius | rounded-card |
--shadow-* |
Box shadows | shadow-card |
--ease-* |
Timing functions | ease-fluid |
--animate-* |
Animations | animate-fade-in |
--blur-* |
Blur filters | blur-card |
--perspective-* |
3D perspective | perspective-card |
--aspect-* |
Aspect ratios | aspect-cinema |
Key Concepts
--color-*: initialresets all default colors before defining custom ones--*: initialresets the entire default theme@theme inlineprevents CSS variable resolution issues when referencing other variables@theme staticgenerates CSS variables even when utilities are unused@keyframescan be defined inside@themefor animation tokens
For implementation examples, see examples/core.md.
Pattern 6: Custom Utilities with @utility
The @utility directive replaces v3's @layer utilities {}. Supports static utilities, functional utilities with --value(), and modifiers with --modifier().
Types of Custom Utilities
- Static: Fixed CSS declarations (
@utility content-auto { content-visibility: auto; }) - Functional: Accept values via
--value()(@utility tab-* { tab-size: --value(integer); }) - With modifiers: Optional modifiers via
--modifier()for secondary values
Value Resolution
--value(--namespace-*)matches theme variables--value(integer)matches bare integer values--value([length])matches arbitrary values in brackets- Multiple
--value()declarations cascade (last match wins)
For implementation examples, see examples/advanced.md.
Pattern 7: Custom Variants with @custom-variant
The @custom-variant directive replaces v3's addVariant() plugin API. Define conditional styling rules in CSS.
Syntax Forms
- Shorthand:
@custom-variant name (selector); - Block:
@custom-variant name { /* rules with @slot */ } - Complex: Supports
@media,@supports, nested selectors with@slotplaceholder
For implementation examples, see examples/advanced.md.
Pattern 8: Container Queries
Container queries are built into v4 core (no plugin needed). Style elements based on container size, not viewport.
Key Concepts
@containermakes an element a query container@sm:,@md:,@lg:apply at container breakpoints (not viewport)@max-sm:,@max-md:for max-width container queries@min-md:@max-xl:for range queries- Named containers with
@container/nameand@sm/name:
For implementation examples, see examples/advanced.md.
Pattern 9: 3D Transforms and Modern CSS
Tailwind v4 adds first-class 3D transform utilities and leverages modern CSS features.
3D Transform Utilities
rotate-x-*,rotate-y-*,rotate-z-*for 3D rotationtranslate-z-*for depth translationscale-z-*for depth scalingperspective-*andperspective-origin-*for 3D perspectivetransform-3dto enable 3D transform contextbackface-hidden/backface-visiblefor card-flip effects
Other Modern Features
@starting-styleviastarting:variant for enter/exit animationsfield-sizing-contentfor auto-resizing textareascolor-scheme-darkfor native dark mode scrollbarsinset-shadow-*andinset-ring-*for layered box shadows
For implementation examples, see examples/advanced.md.
Pattern 10: Component Extraction with cn()
For React components, use cn() (clsx + tailwind-merge) to handle class composition and conflict resolution. Works with CVA for variant-based components.
Key Concepts
cn()combinesclsx(conditional classes) withtwMerge(conflict resolution)- External
classNameprop should always be last incn()to allow overrides - Use CVA for variant-heavy components,
cn()for simple composition - Never use
@applyfor component extraction in React (usecn()instead)
For implementation examples, see examples/advanced.md.
<decision_framework>
Decision Framework
When to Use Which Styling Approach
Need component variants (size, intent, state)?
|-- YES --> Use CVA + cn() + Tailwind classes
|-- NO --> Just utility classes in markup
Need custom utility not in Tailwind?
|-- YES --> Is it a single fixed style?
| |-- YES --> @utility name { declarations }
| |-- NO --> @utility name-* { --value() }
|-- NO --> Use built-in utilities
Need conditional styling based on parent/sibling state?
|-- YES --> Is parent state?
| |-- YES --> group/group-* pattern
| |-- NO --> peer/peer-* pattern
|-- NO --> Direct state variants (hover:, focus:)
Need responsive behavior based on...?
|-- Viewport size --> sm:/md:/lg: breakpoint variants
|-- Container size --> @container + @sm:/@md: variants
|-- Neither --> Static styling
Dark Mode Strategy
Is dark mode automatic (system preference only)?
|-- YES --> No config needed (default prefers-color-scheme)
|-- NO --> Need manual toggle?
|-- YES --> Using class on <html>?
| |-- YES --> @custom-variant dark (&:where(.dark, .dark *))
| |-- NO --> @custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *))
|-- NO --> Default media query
Theme Customization Scope
Need to add a few custom tokens?
|-- YES --> Add to @theme alongside defaults
Need to replace an entire namespace?
|-- YES --> --namespace-*: initial; then define custom tokens
Need fully custom theme (no defaults)?
|-- YES --> --*: initial; then define everything
Need to share theme across projects?
|-- YES --> Create shared theme.css, import with @import
v3 to v4 Migration Decision
Is the project actively maintained?
|-- YES --> Does it use tailwind.config.js plugins?
| |-- YES --> Can plugins be replaced with @utility/@custom-variant?
| | |-- YES --> Migrate to v4
| | |-- NO --> Keep v3 or use @config/@plugin compatibility
| |-- NO --> Migrate to v4 (run npx @tailwindcss/upgrade)
|-- NO --> Stay on v3.4 (stable, still supported)
</decision_framework>
Integration Guide
Works with:
- React: Use
cn()for class composition,classNameprop forwarding, CVA for variants - CVA (class-variance-authority): Define Tailwind classes in variant objects, use
tailwind-mergefor conflict resolution - Next.js: Use
@tailwindcss/postcss(App Router) or@tailwindcss/vite(if Vite-based) - Vite: Use
@tailwindcss/viteplugin for best performance - PostCSS: Use
@tailwindcss/postcssfor non-Vite bundlers - tailwind-merge: Resolves class conflicts when composing/overriding Tailwind classes
- Prettier plugin:
prettier-plugin-tailwindcssfor automatic class sorting
Replaces / Conflicts with:
- SCSS Modules: Tailwind replaces SCSS Modules entirely -- do not mix in the same project
- CSS-in-JS (styled-components, Emotion): Tailwind replaces runtime CSS-in-JS solutions
- PostCSS plugins:
autoprefixerandpostcss-importare NOT needed with v4
Does NOT replace:
- CSS animations / @keyframes: Use
@themeto define animation tokens, but complex animations may still need custom CSS - CSS variables for runtime values: Use
var()or arbitrary valuesbg-(--my-var)alongside Tailwind
<red_flags>
RED FLAGS
High Priority Issues:
- Using
tailwind.config.jswithout@configdirective (v4 does NOT auto-detect JS config) - Using
@tailwind base; @tailwind components; @tailwind utilities;(v3 syntax, use@import "tailwindcss") - Using
@layer utilities {}for custom utilities (use@utilitydirective) - Using
tailwindcssdirectly as PostCSS plugin (use@tailwindcss/postcss) - Using
!fleximportant syntax (v4 usesflex!-- trailing not leading) - Using
bg-[--my-var]for CSS variables (v4 usesbg-(--my-var)with parentheses) - Using hex/rgb colors in
@theme(use oklch for P3 gamut support) - Assuming
borderdefaults togray-200(v4 defaults tocurrentColor) - Assuming
ringdefaults to3px(v4 defaults to1px)
Medium Priority Issues:
- Using
@applyfor React component extraction (usecn()with tailwind-merge instead) - Not specifying
@sourcefor node_modules UI libraries (automatic detection skips node_modules) - Using Sass/Less/Stylus with Tailwind v4 (not supported -- v4 is a standalone preprocessor)
- Using
autoprefixerorpostcss-import(not needed with v4) - Using
transform-noneto reset transforms (v4 uses individual properties, usescale-none/rotate-0)
Common Mistakes:
- Forgetting
@custom-variant darkwhen using class-based dark mode toggle - Using
content: ['./src/**/*.tsx'](v4 auto-detects, nocontentarray) - Mixing v3 and v4 syntax in the same project
- Not running
npx @tailwindcss/upgradefor automated migration
Gotchas and Edge Cases:
- Variant stacking order changed: v3 was right-to-left, v4 is left-to-right (follows CSS cascade)
hover:only triggers on devices with hover capability (no phantom hover on touch devices)space-y-*/divide-*changed selectors: v3 used:not([hidden]) ~ :not([hidden]), v4 uses:not(:last-child)-- prefergap-*with flex/grid- Grid template values use underscores for spaces:
grid-cols-[max-content_auto](not commas) shadow-smin v3 =shadow-xsin v4,shadowin v3 =shadow-smin v4 (whole scale shifted)rounded-smin v3 =rounded-xsin v4,roundedin v3 =rounded-smin v4outline-nonein v3 =outline-hiddenin v4 (accessibility improvement)ringin v3 (3px) =ring-3in v4 (default is now 1px)- Browser requirements: Safari 16.4+, Chrome 111+, Firefox 128+ (no IE11, no older browsers)
</red_flags>
<critical_reminders>
⚠️ CRITICAL REMINDERS
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST use @import "tailwindcss" and @theme for configuration - NEVER use tailwind.config.js, @tailwind base, or module.exports)
(You MUST use @utility for custom utilities - NEVER use @layer utilities {} (v3 syntax))
(You MUST use oklch or CSS variable references for custom colors in @theme - NEVER use hex/rgb for theme tokens)
(You MUST use @tailwindcss/vite for Vite projects and @tailwindcss/postcss for others - NEVER use tailwindcss directly as PostCSS plugin)
(You MUST specify border colors explicitly - v4 defaults to currentColor not gray-200)
Failure to follow these rules will produce v3 code that does not work with Tailwind CSS v4.
</critical_reminders>