Write, debug, and tune Playwright specs with locator strategy, trace diagnosis, and CI-aware timeouts.
Coding
ia-tailwind-css
Try itTailwind 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.
| Directive | Purpose |
|---|---|
@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
gapoverspace-x/space-y-- gap handles wrapping; space-* breaks on wrapsize-*overw-* h-*-- for equal dimensionsmin-h-dvhovermin-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
@themebefore using[#hex] - Never construct classes dynamically --
text-${color}-500won't be detected; use complete class names @utilityover@applywith@layer--@applyon@layerclasses 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-- catchestext-red-500 text-blue-500no-unknown-classes-- flags typosenforce-canonical-classes-- normalizes shorthandno-duplicate-classes-- removes redundant entriesno-deprecated-classes-- catches v3 classes removed in v4useSortedClasses-- enforces canonical class order; configureattributes: ["classList"]andfunctions: ["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
| Symptom | Fix |
|---|---|
bg-primary doesn't work | Add @theme inline { --color-primary: var(--primary); } |
| Colors all black/white | Double hsl() wrapping -- use var(--color) not hsl(var(--color)) |
@apply fails on custom class | Use @utility instead of @layer components |
| Build fails after migration | Delete tailwind.config.ts |
| Animations broken | Replace tailwindcss-animate with tw-animate-css |
.dark { @theme { } } fails | v4 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 buildor equivalent) - No v3 class names remain in changed files (check with
@tailwindcss/upgrade --dry-runif 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.
Stores durable facts in a categorized, plain-markdown vault on disk, alongside your agent's built-in memory.
Find why your productivity system keeps failing, then apply the smallest fix — capacity math, bottleneck routing, durable local notes.
Join a video meeting as an AI bot with voice, avatar, and screenshare across four operating modes.
Fetch raw ad creative, app, ranking, and revenue data from AdMapix as structured JSON.
More from iliaal
Browse all skillsLaravel and PHP 8.4 framework-level guidance covering architecture, Eloquent, migrations, queues, and testing, grounded in real failure modes.
Run spec-first code reviews with severity-ranked findings and an optional multi-agent deep mode.
Diagnoses software bugs through a 7-step process anchored to a failing reproduction before any fix.
Get an approved design document before writing a single line of code.
Write tests that verify real behavior—not mocks—with named scenarios, edge cases, and silent-failure coverage.
Structured implementation plans with durable .plan/ state, scoped phases, and explicit decision rules.