Coding

ia-tailwind-css

Try it

Tailwind CSS v4 patterns: CSS-first config, @theme tokens, component variants, and v3 migration fixes.

What it does

Reference patterns for Tailwind CSS v4 projects. Covers CSS-first configuration (@theme, @theme inline, @custom-variant, @utility), design tokens that auto-generate utilities, and how to map CSS variables for dark mode via `@theme inline` without `dark:` variants. Includes coding rules (use `gap` over `space-*`, `min-h-dvh` over `min-h-screen`, never construct class names dynamically), class merging with `cn()`, component variants via `tailwind-variants` or CVA, ESLint rules via `eslint-plugin-better-tailwindcss`, and a common-errors table for broken styling. Also covers v3→v4 migration steps and codemod guidance, plus CSS Modules support via `@reference`.

When to use it

  • Setting up @theme tokens and custom utilities for a new v4 project
  • Migrating an existing v3 codebase to v4
  • Building type-safe component variants with tailwind-variants or CVA
  • Diagnosing broken Tailwind styles, dark mode, or migration build errors

The skill document

Tailwind CSS v4

Verify before implementing: For v4-specific syntax (@theme, @variant, CSS-first config), look up current docs via Context7 (query-docs) before writing code. Tailwind v4 changed significantly from v3 and training data may be stale.

CSS-First Configuration

v4 eliminates tailwind.config.ts. All configuration lives in CSS.

DirectivePurpose
@import "tailwindcss"Entry point (replaces @tailwind base/components/utilities)
@theme { }Define/extend design tokens -- auto-generates utility classes
@theme inline { }Map CSS variables to Tailwind utilities without generating new vars
@theme static { }Define tokens that don't generate utilities
@utility name { }Create custom utilities (replaces @layer components + @apply)
@custom-variant name (selector)Define custom variants
@import "tailwindcss";

@theme {
  --color-brand: oklch(0.72 0.11 178);
  --font-display: "Inter", sans-serif;
  --animate-fade-in: fade-in 0.2s ease-out;
  @keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
}

@custom-variant dark (&:where(.dark, .dark *));

Tokens defined with @theme become utilities automatically: --color-brand produces bg-brand, text-brand, border-brand. Define z-index as tokens (--z-modal: 50) and reference via z-(--z-modal) instead of arbitrary z-50.

CSS Modules: when using .module.css with Tailwind v4, add @reference "#tailwind"; at the top of the module file to enable theme token access inside the module.

Animations (tw-animate-css): use animate-in/animate-out base classes combined with effect classes (fade-in, slide-in-from-top). Decimal spacing gotcha: use bracket notation [0.625rem] instead of fractional values like 2.5.

v3 to v4 Migration

For projects upgrading from v3 to v4, see v3-to-v4-migration.md for the full breaking-change table and codemod guidance. For greenfield v4 work, current patterns are above.

Coding Rules

  • gap over space-x/space-y -- gap handles wrapping; space-* breaks on wrap
  • size-* over w-* h-* -- for equal dimensions
  • min-h-dvh over min-h-screen -- dvh accounts for mobile browser chrome
  • Opacity modifier (bg-black/50) -- *-opacity-* utilities are removed in v4
  • Design tokens over arbitrary values -- check @theme before using [#hex]
  • Never construct classes dynamically -- text-${color}-500 won't be detected; use complete class names
  • @utility over @apply with @layer -- @apply on @layer classes fails in v4
  • Parent padding over last-child margin -- use padding on containers instead of bottom margins on the last child

ESLint Integration

Use eslint-plugin-better-tailwindcss for automated class validation:

  • no-conflicting-classes -- catches text-red-500 text-blue-500
  • no-unknown-classes -- flags typos
  • enforce-canonical-classes -- normalizes shorthand
  • no-duplicate-classes -- removes redundant entries
  • no-deprecated-classes -- catches v3 classes removed in v4
  • useSortedClasses -- enforces canonical class order; configure attributes: ["classList"] and functions: ["clsx", "cva", "cn", "tv", "tw"] to cover JSX utility functions

Class Merging

Use cn() combining clsx + tailwind-merge for conditional/dynamic classes. Use plain strings for static className attributes.

import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }
// Static: plain string


// Conditional: use cn()

Component Variants

Use tailwind-variants (tv()) for type-safe variant components. Alternative: class-variance-authority (cva()).

import { tv } from "tailwind-variants";
const button = tv({
  base: "rounded-lg px-4 py-2 font-medium transition-colors",
  variants: {
    color: { primary: "bg-blue-600 text-white", secondary: "bg-gray-200 text-gray-800" },
    size: { sm: "text-sm px-3 py-1", md: "text-base", lg: "text-lg px-6 py-3" },
  },
  defaultVariants: { color: "primary", size: "md" },
});

See tailwind-variants patterns for slots, composition, and responsive variants.

Common Errors

SymptomFix
bg-primary doesn't workAdd @theme inline { --color-primary: var(--primary); }
Colors all black/whiteDouble hsl() wrapping -- use var(--color) not hsl(var(--color))
@apply fails on custom classUse @utility instead of @layer components
Build fails after migrationDelete tailwind.config.ts
Animations brokenReplace tailwindcss-animate with tw-animate-css
.dark { @theme { } } failsv4 does not support nested @theme -- use :root/.dark CSS vars mapped via @theme inline

Dark Mode (v4 Pattern)

:root { --background: hsl(0 0% 100%); --foreground: hsl(222 84% 4.9%); }
.dark { --background: hsl(222 84% 4.9%); --foreground: hsl(210 40% 98%); }
@theme inline { --color-background: var(--background); --color-foreground: var(--foreground); }

Semantic classes (bg-background, text-foreground) auto-switch -- no dark: variants needed for themed colors.

Verify

  • Build passes with zero errors (npm run build or equivalent)
  • No v3 class names remain in changed files (check with @tailwindcss/upgrade --dry-run if available)
  • No conflicting classes on the same element

References

  • Component patterns -- tailwind-variants slots, CVA, compound components
  • Layout patterns -- grid areas, container queries, z-index management, fluid typography

Questions people ask

What is the difference between @theme and @theme inline?
@theme defines or extends design tokens and auto-generates utility classes from them (e.g., --color-brand produces bg-brand, text-brand). @theme inline maps existing CSS variables to Tailwind utilities without creating new variables — useful for wiring :root/.dark custom properties to semantic classes like bg-background.
Can I dynamically construct class names like text-${color}-500?
No. The document explicitly warns that dynamic class construction won't be detected by Tailwind's compiler, so the utility won't be emitted. Always use complete, statically-present class names.
How does this work with CSS Modules?
Add @reference "#tailwind"; at the top of a .module.css file to enable theme token access inside the module. The skill also notes double hsl() wrapping is a common breakage when migrating v3 CSS-variable patterns.

Related skills

Generate and edit Draw.io, Mermaid, and Excalidraw diagrams from natural language using a structured JSON spec.

by nssa.io1.0k installs47 stars

Stores durable facts in a categorized, plain-markdown vault on disk, alongside your agent's built-in memory.

by Iván559 installs18 stars

Find why your productivity system keeps failing, then apply the smallest fix — capacity math, bottleneck routing, durable local notes.

by Iván855 installs69 stars

Join a video meeting as an AI bot with voice, avatar, and screenshare across four operating modes.

by johnpatternai22 installs8 stars

Fetch raw ad creative, app, ranking, and revenue data from AdMapix as structured JSON.

by fly0pants4.3k installs296 stars

More from iliaal

Browse all skills

Laravel and PHP 8.4 framework-level guidance covering architecture, Eloquent, migrations, queues, and testing, grounded in real failure modes.

by iliaal40 installs

Run spec-first code reviews with severity-ranked findings and an optional multi-agent deep mode.

by iliaal37 installs

Diagnoses software bugs through a 7-step process anchored to a failing reproduction before any fix.

by iliaal36 installs

Get an approved design document before writing a single line of code.

by iliaal33 installs

Write tests that verify real behavior—not mocks—with named scenarios, edge cases, and silent-failure coverage.

by iliaal33 installs

Structured implementation plans with durable .plan/ state, scoped phases, and explicit decision rules.

by iliaal30 installs