tailwind-css
This skill should be used when the user asks to "style with Tailwind", "add Tailwind classes", "fix Tailwind styles", "use tailwind-variants", "add animations with tw-animate-css", "configure Tailwind v4", "migrate to Tailwind v4", or mentions Tailwind utilities, CSS classes, responsive design, dark mode, gradients, design tokens, or CSS Modules.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install paulrberg-agent-skills-tailwind-css
Repository
Skill path: skills/tailwind-css
This skill should be used when the user asks to "style with Tailwind", "add Tailwind classes", "fix Tailwind styles", "use tailwind-variants", "add animations with tw-animate-css", "configure Tailwind v4", "migrate to Tailwind v4", or mentions Tailwind utilities, CSS classes, responsive design, dark mode, gradients, design tokens, or CSS Modules.
Open repositoryBest for
Primary workflow: Design Product.
Technical facets: Full Stack, Frontend, Designer.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: PaulRBerg.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install tailwind-css into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/PaulRBerg/agent-skills before adding tailwind-css to shared team environments
- Use tailwind-css for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: tailwind-css
user-invocable: false
description: This skill should be used when the user asks to "style with Tailwind", "add Tailwind classes", "fix Tailwind styles", "use tailwind-variants", "add animations with tw-animate-css", "configure Tailwind v4", "migrate to Tailwind v4", or mentions Tailwind utilities, CSS classes, responsive design, dark mode, gradients, design tokens, or CSS Modules.
---
# Tailwind CSS v4
Expert guidance for Tailwind CSS v4, CSS-first configuration, modern utility patterns, and type-safe component styling with tailwind-variants.
## CSS-First Configuration
Tailwind CSS v4 eliminates `tailwind.config.ts` in favor of CSS-only configuration. All configuration lives in CSS files using special directives.
**Core Directives:**
- `@import "tailwindcss"` - Entry point that loads Tailwind
- `@theme { }` - Define or extend design tokens
- `@theme static { }` - Define tokens that should not generate utilities
- `@utility` - Create custom utilities
- `@custom-variant` - Define custom variants
**Minimal Example:**
```css
@import "tailwindcss";
@theme {
--color-brand: oklch(0.72 0.11 178);
--font-display: "Inter", sans-serif;
--spacing-edge: 1.5rem;
}
```
All theme tokens defined with `@theme` automatically become available as utility classes. For example, `--color-brand` can be used as `bg-brand`, `text-brand`, `border-brand`, etc.
## ESLint Integration
Use `eslint-plugin-better-tailwindcss` for Tailwind CSS v4 class validation and style enforcement.
**Correctness Rules (errors):**
- `no-conflicting-classes` - Detect classes that override each other
- `no-unknown-classes` - Flag classes not registered with Tailwind
**Stylistic Rules (warnings):**
- `enforce-canonical-classes` - Use standard v4 class names
- `enforce-shorthand-classes` - Use abbreviated class versions
- `no-deprecated-classes` - Remove outdated class names
- `no-duplicate-classes` - Eliminate redundant declarations
- `no-unnecessary-whitespace` - Clean up extra spacing
**Examples:**
```typescript
// ❌ Bad: separate padding
<div className="px-6 py-6">
// ✅ Good: shorthand
<div className="p-6">
```
```typescript
// ❌ Bad: separate width/height
<div className="w-6 h-6">
// ✅ Good: size utility
<div className="size-6">
```
Run the project's ESLint check after modifying Tailwind classes to validate all changes across the codebase.
## Coding Preferences
### Layout and Spacing
**Use `gap` for flex/grid spacing, not `space-x`/`space-y`:**
The `gap` utilities handle wrapping correctly, while `space-*` utilities break when flex/grid items wrap to multiple lines.
```typescript
// ✅ Good: gap handles wrapping
<div className="flex gap-4">
// ❌ Bad: breaks when items wrap
<div className="flex space-x-4">
```
**Prefer `size-*` over separate `w-*`/`h-*` for equal dimensions:**
```typescript
// ✅ Good: concise
<div className="size-16">
// ❌ Bad: redundant
<div className="w-16 h-16">
```
**Always use `min-h-dvh` instead of `min-h-screen`:**
Dynamic viewport height (`dvh`) accounts for mobile browser chrome, while `vh` units ignore it and cause layout issues on mobile Safari.
```typescript
// ✅ Good: works on mobile Safari
<main className="min-h-dvh">
// ❌ Bad: buggy on mobile Safari
<main className="min-h-screen">
```
**Prefer top/left margins over bottom/right:**
Consistent directionality improves layout predictability.
```typescript
// ✅ Good: top margin
<div className="mt-4">
// ❌ Avoid: bottom margin (unless needed)
<div className="mb-4">
```
**Use padding on parent containers instead of bottom margins on last child:**
Padding provides consistent spacing without needing `:last-child` selectors.
```typescript
// ✅ Good: padding on parent
<section className="pb-8">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</section>
// ❌ Avoid: margin on children
<section>
<div className="mb-4">Item 1</div>
<div className="mb-4">Item 2</div>
<div>Item 3</div>
</section>
```
**For max-widths, prefer container scale over pixel values:**
```typescript
// ✅ Good: semantic container size
<div className="max-w-2xl">
// ❌ Avoid: arbitrary pixel value
<div className="max-w-[672px]">
```
### Typography
**Avoid `leading-*` classes; use line height modifiers:**
Tailwind v4 supports inline line height modifiers with the `text-{size}/{leading}` syntax.
```typescript
// ✅ Good: combined size and line height
<p className="text-base/7">
// ❌ Bad: separate utilities
<p className="text-base leading-7">
```
**Font Size Reference:**
| Class | Size |
| ----------- | ---- |
| `text-xs` | 12px |
| `text-sm` | 14px |
| `text-base` | 16px |
| `text-lg` | 18px |
| `text-xl` | 20px |
### Colors and Opacity
**Use opacity modifier syntax, not separate opacity utilities:**
All `*-opacity-*` utilities were removed in Tailwind v4. Use the modifier syntax instead.
```typescript
// ✅ Good: opacity modifier
<div className="bg-red-500/60">
// ❌ Bad: removed in v4
<div className="bg-red-500 bg-opacity-60">
```
**Prefer design tokens over arbitrary hex values:**
Check the project's `@theme` configuration before using arbitrary color values.
```typescript
// ✅ Good: theme token
<div className="bg-brand">
// ❌ Avoid: arbitrary hex (check theme first)
<div className="bg-[#4f46e5]">
```
### Border Radius
Tailwind v4 renamed border radius utilities:
| v3 | v4 (equivalent) | Size |
| ------------ | --------------- | ---- |
| `rounded-sm` | `rounded-xs` | 2px |
| `rounded` | `rounded-sm` | 4px |
| `rounded-md` | `rounded` | 6px |
| `rounded-lg` | `rounded-md` | 8px |
Use the v4 names when writing new code.
### Gradients
Tailwind v4 renamed gradient utilities and added new gradient types.
**Use `bg-linear-*`, not `bg-gradient-*`:**
```typescript
// ✅ Good: v4 syntax
<div className="bg-linear-to-r from-blue-500 to-purple-500">
// ❌ Bad: removed in v4
<div className="bg-gradient-to-r from-blue-500 to-purple-500">
```
**New gradient types:**
- `bg-radial` - Radial gradients
- `bg-conic` - Conic gradients
**Example:**
```typescript
<div className="bg-radial from-blue-500 to-purple-500">
<div className="bg-conic from-red-500 via-yellow-500 to-green-500">
```
### Arbitrary Values
**Always prefer Tailwind's predefined scale:**
Check the project's `@theme` configuration for available tokens before using arbitrary values.
```typescript
// ✅ Good: predefined scale
<div className="ml-4">
// ❌ Avoid: arbitrary pixel value
<div className="ml-[16px]">
```
**General rule:** Prefer sizing scale over pixel values. Three similar lines of code is better than a premature abstraction.
### Class Merging
The common pattern is a `cn` utility combining `clsx` + `tailwind-merge`.
**Use `cn` for:**
- Static constants: `const CARD_BASE = cn("fixed classes")`
- Conditional classes: `cn("base", condition && "conditional")`
- Dynamic merging: `cn(baseClasses, className)`
- Conflict resolution: `cn("p-4", "p-6")` → `"p-6"`
**Do NOT use `cn` for:**
- Static strings in `className` attributes: `className="fixed classes"`
**Examples:**
```typescript
// ✅ Good: static string in className
<button className="rounded-lg px-4 py-2 font-medium bg-blue-600">
// ✅ Good: static constant with cn
const CARD_BASE = cn("rounded-lg border border-gray-300 p-4");
<div className={CARD_BASE} />
// ✅ Good: conditional with cn
<button className={cn(
"rounded-lg px-4 py-2 font-medium",
isActive ? "bg-blue-600" : "bg-gray-700",
disabled && "opacity-50"
)} />
// ❌ Bad: unnecessary cn for static className attribute
<button className={cn("rounded-lg px-4 py-2 font-medium")} />
```
### Image Sizing
Use Tailwind size classes instead of pixel values for `Image` components.
```typescript
// ✅ Good: Tailwind units
<Image src={src} alt={alt} className="size-16" />
<Image src={src} alt={alt} className="w-24 h-auto" />
// ❌ Bad: pixel values
<Image src={src} alt={alt} width={64} height={64} />
```
### Z-Index
Define z-index values as CSS custom properties in `@theme`, then reference them with the `z-(--z-*)` syntax.
**Never use arbitrary z-index numbers:**
```typescript
// ✅ Good: theme z-index value
<div className="z-(--z-modal)">
<div className="z-(--z-sticky)">
// ❌ Bad: arbitrary z-index numbers
<div className="z-[100]">
<div className="z-[9999]">
```
**Define z-index tokens in CSS:**
```css
@theme {
--z-base: 0;
--z-sticky: 10;
--z-modal: 100;
--z-tooltip: 1000;
}
```
### Dark Mode
Use the plain `dark:` variant for dark mode styles.
**Pattern:**
Write light mode styles first, then add dark mode overrides.
```typescript
// ✅ Good: light mode first, then dark override
<div className="bg-white text-gray-900 dark:bg-gray-900 dark:text-white">
// ❌ Avoid: dark mode first (less readable)
<div className="dark:bg-gray-900 dark:text-white bg-white text-gray-900">
```
## CSS Modules
Use CSS Modules only as a last resort for complex CSS that cannot be easily written with Tailwind classes.
All `.module.css` files must include `@reference "#tailwind";` at the top to enable Tailwind utilities and theme tokens inside the module.
**Example:**
```css
/* component.module.css */
@reference "#tailwind";
.component {
/* Complex CSS that can't be expressed with Tailwind utilities */
/* Can still use Tailwind utilities and theme tokens */
}
```
## Common Tasks
### Adding a Component with Variants
1. Read `references/tailwind-variants.md` for patterns
2. Check the project's `@theme` configuration for available tokens
3. Use `tv()` from `tailwind-variants` for type-safe variants
**Example:**
```typescript
import { tv } from "tailwind-variants";
const button = tv({
base: "rounded-lg px-4 py-2 font-medium",
variants: {
color: {
primary: "bg-blue-600 text-white",
secondary: "bg-gray-600 text-white",
},
size: {
sm: "text-sm",
md: "text-base",
lg: "text-lg",
},
},
});
```
### Debugging Styles
1. Check `references/tailwind-v4-rules.md` for breaking changes
2. Verify gradient syntax (`bg-linear-*`, not `bg-gradient-*`)
3. Verify CSS variable syntax (`bg-my-color`, not `bg-[--var-my-color]`)
4. Check if arbitrary value exists in the project's `@theme` configuration
### Working with Colors
1. Check the project's `@theme` configuration first to see available colors
2. Use semantic color names when available
3. Use opacity modifiers for transparency (`/20`, `/50`, etc.)
4. Avoid arbitrary colors unless absolutely necessary
**Example:**
```typescript
// ✅ Good: theme token with opacity
<div className="bg-brand/20 text-brand">
// ❌ Avoid: arbitrary hex
<div className="bg-[#4f46e5]/20 text-[#4f46e5]">
```
### Adding Animations
1. Read `references/tw-animate-css.md` for available animations
2. Combine a base class (`animate-in` or `animate-out`) with effect classes
3. Note decimal spacing gotcha: use `[0.625rem]` syntax, not `2.5`
**Example:**
```typescript
// Enter: fade + slide up
<div className="fade-in slide-in-from-bottom-4 duration-300 animate-in">
// Exit: fade + slide down
<div className="fade-out slide-out-to-bottom-4 duration-200 animate-out">
```
## Quick Reference Table
| Aspect | Pattern |
| ------------------ | ------------------------------------------------- |
| Configuration | CSS-only: `@theme`, `@utility`, `@custom-variant` |
| Gradients | `bg-linear-*`, `bg-radial`, `bg-conic` |
| Opacity | Modifier syntax: `bg-black/50` |
| Line Height | Modifier syntax: `text-base/7` |
| Font Features | `font-features-zero`, `font-features-ss01`, etc. |
| CSS Variables | `bg-my-color` (auto-created from `@theme`) |
| CSS Modules | `@reference "#tailwind";` at top |
| Class Merging | `cn()` for conditionals; plain string for static |
| Viewport | `min-h-dvh` (not `min-h-screen`) |
| Component Variants | `references/tailwind-variants.md` |
| Animations | `references/tw-animate-css.md` |
| V4 Rules | `references/tailwind-v4-rules.md` |
## Reference Documentation
- **Tailwind v4 Rules & Best Practices:** `references/tailwind-v4-rules.md` — Breaking changes, removed/renamed utilities, layout rules, typography, gradients, CSS variables, new v4 features, common pitfalls
- **tailwind-variants Patterns:** `references/tailwind-variants.md` — Component variants, slots API, composition, TypeScript integration, responsive variants
- **tw-animate-css Reference:** `references/tw-animate-css.md` — Enter/exit animations, slide/fade/zoom utilities, spacing gotchas
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### references/tailwind-variants.md
```markdown
# tailwind-variants Best Practices
## Overview
**tailwind-variants** provides a first-class variant API for composable, type-safe component styling with automatic Tailwind class conflict resolution.
**Key Benefits:**
- Type-safe variant definitions with full TypeScript support
- Automatic class conflict resolution (via tailwind-merge)
- 37-62% faster than alternatives (v2+), 500x faster with v3
- Framework-agnostic (React, Vue, Svelte, vanilla JS)
## Installation
```bash
bun add tailwind-variants
```
**Build Options:**
```typescript
// Original build (with tailwind-merge, automatic conflict resolution)
import { tv } from "tailwind-variants";
// Lite build (~80% smaller, no conflict resolution)
import { tv } from "tailwind-variants/lite";
```
## Core API
### Basic Usage
```typescript
import { tv } from "tailwind-variants";
const button = tv({
base: "font-medium rounded-lg transition-colors",
variants: {
color: {
primary: "bg-primary text-white hover:bg-primary/90",
secondary: "bg-secondary text-white hover:bg-secondary/90",
},
size: {
sm: "text-sm px-3 py-1.5",
md: "text-base px-4 py-2",
lg: "text-lg px-6 py-3",
},
},
defaultVariants: {
color: "primary",
size: "md",
},
});
// Usage
button(); // Uses defaults
button({ color: "secondary", size: "lg" });
```
### Boolean Variants
Use boolean variants for conditional states:
```typescript
const input = tv({
base: "w-full rounded-md border px-3 py-2",
variants: {
disabled: {
true: "opacity-50 cursor-not-allowed",
},
error: {
true: "border-red-500 focus:ring-red-500",
},
},
});
// Usage
input({ disabled: true, error: false });
```
### Compound Variants
Apply styles when multiple conditions are met:
```typescript
const button = tv({
variants: {
color: {
primary: "bg-blue-500",
secondary: "bg-gray-500",
},
disabled: {
true: "opacity-50",
},
},
compoundVariants: [
{
color: "primary",
disabled: true,
class: "bg-blue-300", // Override when both conditions match
},
],
});
```
## Slots API (Multi-Part Components)
Use slots for complex components with multiple elements:
```typescript
const card = tv({
slots: {
base: "rounded-lg shadow-md bg-white overflow-hidden",
header: "px-6 py-4 border-b border-gray-200",
body: "px-6 py-4",
footer: "px-6 py-4 bg-gray-50 border-t border-gray-200",
},
variants: {
size: {
sm: {
header: "px-4 py-2 text-sm",
body: "px-4 py-2 text-sm",
footer: "px-4 py-2 text-sm",
},
lg: {
header: "px-8 py-6 text-lg",
body: "px-8 py-6 text-lg",
footer: "px-8 py-6 text-lg",
},
},
},
});
// Usage
const { base, header, body, footer } = card({ size: "lg" });
// In React
<div className={base()}>
<div className={header()}>Header</div>
<div className={body()}>Content</div>
<div className={footer()}>Footer</div>
</div>;
```
### Compound Slots
Apply classes to multiple slots based on conditions:
```typescript
const card = tv({
slots: {
base: "rounded-lg",
header: "p-4",
body: "p-4",
},
variants: {
bordered: {
true: {},
},
},
compoundSlots: [
{
slots: ["header", "body"], // Apply to both
bordered: true,
class: "border border-gray-200",
},
],
});
```
### Slot Overrides
Override individual slots at runtime:
```typescript
const { base, header, body } = card();
<div className={base()}>
<div className={header({ class: "bg-blue-50" })}>Custom styled header</div>
<div className={body()}>Default styled body</div>
</div>;
```
## Component Composition
### Using `extend` (Recommended)
The `extend` property provides type-safe composition:
```typescript
const baseButton = tv({
base: "font-medium rounded transition-colors",
variants: {
size: {
sm: "text-sm px-3 py-1",
md: "text-base px-4 py-2",
},
},
});
const primaryButton = tv({
extend: baseButton, // Inherits all config
base: "bg-primary text-white hover:bg-primary/90",
variants: {
outlined: {
true: "bg-transparent border border-primary text-primary",
},
},
});
// Has both 'size' and 'outlined' variants
primaryButton({ size: "sm", outlined: true });
```
**Benefits:**
- Automatic merging of variants, slots, defaultVariants, and compoundVariants
- Full TypeScript autocomplete
- Override inherited configurations
## Responsive Variants
Use Tailwind's responsive prefixes directly in variants:
```typescript
const container = tv({
base: "px-4 md:px-6 lg:px-8",
variants: {
maxWidth: {
sm: "max-w-sm md:max-w-md",
md: "max-w-md md:max-w-lg",
lg: "max-w-lg md:max-w-xl lg:max-w-2xl",
},
},
});
```
## TypeScript Integration
### Extract Variant Types
Use `VariantProps` to generate type-safe props:
```typescript
import { type VariantProps } from "tailwind-variants";
const button = tv({
variants: {
color: { primary: "...", secondary: "..." },
size: { sm: "...", md: "...", lg: "..." },
},
});
type ButtonVariants = VariantProps<typeof button>;
// { color?: "primary" | "secondary"; size?: "sm" | "md" | "lg" }
interface ButtonProps extends ButtonVariants {
children: React.ReactNode;
}
```
### Required Variants
Make specific variants required:
```typescript
type ButtonVariants = VariantProps<typeof button>;
interface ButtonProps
extends Omit<ButtonVariants, "size">,
Required<Pick<ButtonVariants, "size">> {
children: React.ReactNode;
}
```
### Type Inference
Use `as const` for proper type inference:
```typescript
const sizes = {
sm: "text-sm px-3 py-1",
md: "text-base px-4 py-2",
} as const;
const button = tv({
variants: { size: sizes },
});
```
## Configuration
### Local Configuration
```typescript
const button = tv(
{
base: "rounded",
},
{
twMerge: true, // Enable tailwind-merge
twMergeConfig: {}, // Custom tailwind-merge config
}
);
```
### Global Configuration
```typescript
import { defaultConfig } from "tailwind-variants";
defaultConfig.twMerge = false;
```
### Custom Instance with `createTV`
Create isolated configurations:
```typescript
import { createTV } from "tailwind-variants";
const tv = createTV({
twMerge: true,
twMergeConfig: {
theme: {
colors: ["primary", "secondary"],
spacing: ["edge", "section"],
},
},
});
```
## Common Patterns
### Button Component
```typescript
const button = tv({
base: "inline-flex items-center justify-center font-medium transition-colors focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50",
variants: {
variant: {
default: "bg-primary text-white hover:bg-primary/90",
destructive: "bg-red-500 text-white hover:bg-red-600",
outline: "border border-input bg-surface-950 hover:bg-accent",
ghost: "hover:bg-accent hover:text-accent-foreground",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "size-10",
},
},
defaultVariants: {
variant: "default",
size: "default",
},
});
```
### Card Component with Slots
```typescript
const card = tv({
slots: {
base: "rounded-lg border bg-card text-card-foreground shadow-sm",
header: "flex flex-col gap-1.5 p-6",
title: "text-2xl font-semibold leading-none tracking-tight",
description: "text-sm text-muted-foreground",
content: "p-6 pt-0",
footer: "flex items-center p-6 pt-0",
},
});
const { base, header, title, description, content, footer } = card();
```
### Input Component with States
```typescript
const input = tv({
base: "flex w-full rounded-md border bg-surface-950 px-3 py-2 text-sm transition-colors",
variants: {
variant: {
default: "border-input focus-visible:outline-hidden focus-visible:ring-3 focus-visible:ring-ring",
error: "border-red-500 focus-visible:ring-red-500",
},
disabled: {
true: "cursor-not-allowed opacity-50",
},
},
defaultVariants: {
variant: "default",
},
});
```
## Best Practices
01. **Use `extend` for composition** - Provides type safety and automatic config merging
02. **Leverage compound variants** - Handle complex conditional styling declaratively
03. **Use slots for multi-part components** - Enables granular control
04. **Define default variants** - Reduces repetition in usage
05. **Use boolean variants for states** - Clean API for conditional states
06. **Keep original build unless bundle size critical** - Automatic conflict resolution prevents bugs
07. **Use `VariantProps` for TypeScript** - Extract types automatically
08. **Use `as const` for external definitions** - Ensures proper type inference
09. **Apply responsive prefixes in variants** - Leverage Tailwind's responsive utilities
10. **Reuse `tv()` instances** - Define once, use multiple times
## API Reference
```typescript
tv(options, config);
```
**Options:**
| Property | Type | Description |
| ------------------ | ------------------------------------------------------------------ | ---------------------------- |
| `base` | ClassValue | Base component styles |
| `slots` | Record\<string, ClassValue> | Named style sections |
| `variants` | Record\<string, Record\<string, ClassValue>> | Conditional style variants |
| `defaultVariants` | Record\<string, any> | Default variant values |
| `compoundVariants` | Array\<{ \[variant\]: value, class: ClassValue }> | Multi-condition combinations |
| `compoundSlots` | Array\<{ slots: string[], \[variant\]: value, class: ClassValue }> | Multi-slot combinations |
| `extend` | TVReturnType | Extend another component |
**Config:**
| Property | Type | Default | Description |
| --------------- | ------------- | ------- | -------------------------------- |
| `twMerge` | boolean | true | Enable class conflict resolution |
| `twMergeConfig` | TwMergeConfig | {} | Custom tailwind-merge config |
## Performance Considerations
- **v3 is 500x faster** when using tailwind-merge (vs v2)
- **Reuse `tv()` instances** - Define components once
- **Avoid dynamic class generation** - Pre-define variants
- **Use compound variants judiciously** - Each adds complexity
- **Consider lite build** - ~80% smaller if conflict resolution not needed
## Troubleshooting
**Classes not applying:**
- Ensure `twMerge` is enabled and `tailwind-merge` is installed
- Check class specificity and order
- Verify Tailwind config includes component files
**TypeScript errors:**
- Use `as const` for external variant definitions
- Use `VariantProps` to extract types
- Verify all variant keys match between definition and usage
**Conflict resolution issues:**
- Use original build (not lite) for automatic merging
- Configure `twMergeConfig` for custom theme values
- Ensure `tailwind-merge` is installed
```
### references/tailwind-v4-rules.md
```markdown
# Tailwind CSS Rules and Best Practices
## Core Principles
- **Always use Tailwind CSS v4.2+** - Ensure the codebase is using the latest version
- **Do not use deprecated or removed utilities** - Use the replacement
- **Never use `@apply`** - Use CSS variables, the `--spacing()` function, or framework components instead
- **Check for redundant classes** - Remove any classes that aren't necessary
- **Group elements logically** to simplify responsive tweaks later
## v4 Breaking Changes Reference
### Removed Utilities (removed in v4)
| ❌ Deprecated | ✅ Replacement |
| ----------------------- | ------------------------------------------------- |
| `bg-opacity-*` | Use opacity modifiers like `bg-black/50` |
| `text-opacity-*` | Use opacity modifiers like `text-black/50` |
| `border-opacity-*` | Use opacity modifiers like `border-black/50` |
| `divide-opacity-*` | Use opacity modifiers like `divide-black/50` |
| `ring-opacity-*` | Use opacity modifiers like `ring-black/50` |
| `placeholder-opacity-*` | Use opacity modifiers like `placeholder-black/50` |
| `flex-shrink-*` | `shrink-*` |
| `flex-grow-*` | `grow-*` |
| `overflow-ellipsis` | `text-ellipsis` |
| `decoration-slice` | `box-decoration-slice` |
| `decoration-clone` | `box-decoration-clone` |
### Renamed Utilities (use the v4 name)
| ❌ v3 | ✅ v4 |
| ------------------ | ------------------ |
| `bg-gradient-*` | `bg-linear-*` |
| `shadow-sm` | `shadow-xs` |
| `shadow` | `shadow-sm` |
| `drop-shadow-sm` | `drop-shadow-xs` |
| `drop-shadow` | `drop-shadow-sm` |
| `blur-sm` | `blur-xs` |
| `blur` | `blur-sm` |
| `backdrop-blur-sm` | `backdrop-blur-xs` |
| `backdrop-blur` | `backdrop-blur-sm` |
| `rounded-sm` | `rounded-xs` |
| `rounded` | `rounded-sm` |
| `outline-none` | `outline-hidden` |
| `ring` | `ring-3` |
## Layout and Spacing Rules
### Flexbox and Grid Spacing
#### Always use gap utilities for internal spacing
Gap provides consistent spacing without edge cases (no extra space on last items). It's cleaner and more maintainable
than margins on children.
```html
<!-- ❌ Don't do this -->
<div class="flex">
<div class="mr-4">Item 1</div>
<div class="mr-4">Item 2</div>
<div>Item 3</div>
<!-- No margin on last -->
</div>
<!-- ✅ Do this instead -->
<div class="flex gap-4">
<div>Item 1</div>
<div>Item 2</div>
<div>Item 3</div>
</div>
```
#### Gap vs Space utilities
- **Avoid `space-x-*` and `space-y-*` in flex/grid layouts** - use gap instead
- Space utilities add margins to children and have issues with wrapped items
- Gap works correctly with flex-wrap and all flex directions
```html
<!-- ❌ Avoid space utilities in flex containers -->
<div class="flex flex-wrap space-x-4">
<!-- Space utilities break with wrapped items -->
</div>
<!-- ✅ Use gap for consistent spacing -->
<div class="flex flex-wrap gap-4">
<!-- Gap works perfectly with wrapping -->
</div>
```
### General Spacing Guidelines
- **Prefer top and left margins** over bottom and right margins (unless conditionally rendered)
- **Use padding on parent containers** instead of bottom margins on the last child
- **Always use `min-h-dvh` instead of `min-h-screen`** - `min-h-screen` is buggy on mobile Safari
- **Prefer `size-*` utilities** over separate `w-*` and `h-*` when setting equal dimensions
- For max-widths, prefer the container scale (e.g., `max-w-2xs` over `max-w-72`)
## Typography Rules
### Line Heights
- **Avoid `leading-*` classes** - Use line height modifiers with text size
- **Use fixed line heights from the spacing scale** - Don't use named values
```html
<!-- ❌ Don't do this -->
<p class="text-base leading-7">Text with separate line height</p>
<p class="text-lg leading-relaxed">Text with named line height</p>
<!-- ✅ Do this instead -->
<p class="text-base/7">Text with line height modifier</p>
<p class="text-lg/8">Text with specific line height</p>
```
### Font Size Reference
Be precise with font sizes - know the actual pixel values:
- `text-xs` = 12px
- `text-sm` = 14px
- `text-base` = 16px
- `text-lg` = 18px
- `text-xl` = 20px
## Color and Opacity
### Opacity Modifiers
**Avoid `bg-opacity-*`, `text-opacity-*`, etc.** - use the opacity modifier syntax:
```html
<!-- ❌ Don't do this -->
<div class="bg-red-500 bg-opacity-60">Old opacity syntax</div>
<!-- ✅ Do this instead -->
<div class="bg-red-500/60">Modern opacity syntax</div>
```
## Responsive Design
### Mobile-First Principle
**Tailwind is mobile-first.** This means:
- **Default classes** (without breakpoint prefixes) apply to **all screen sizes**, starting from mobile
- **Breakpoint prefixes** (`md:`, `lg:`, `xl:`, etc.) apply styles at that breakpoint **and above**
- **Never use `sm:` for mobile** — this is a common mistake
**How it works:**
1. Write your mobile styles first (no prefix)
2. Add `md:` prefix for tablet and larger
3. Add `lg:` prefix for desktop and larger
4. Continue with `xl:`, `2xl:`, etc. for even larger screens
**Standard Tailwind breakpoints:**
- `sm` (640px), `md` (768px), `lg` (1024px), `xl` (1280px), `2xl` (1536px)
```html
<!-- ✅ Correct - Mobile first, then scale up -->
<div class="text-sm md:text-base lg:text-lg">
<div class="flex-col md:flex-row">
<div class="px-4 md:px-6 lg:px-8">
<div class="grid-cols-1 md:grid-cols-2 lg:grid-cols-3">
<!-- ✅ Correct - Hide on mobile, show on desktop -->
<div class="hidden lg:block">
<!-- ❌ Wrong - Don't use sm: for mobile (it's redundant) -->
<div class="sm:text-sm md:text-base"> <!-- Just use text-sm -->
<!-- ❌ Wrong - Don't start with larger screens -->
<div class="lg:text-lg md:text-base"> <!-- Wrong order -->
```
**Key principle:** Think mobile-first, then progressively enhance for larger screens.
### Breakpoint Optimization
- **Check for redundant classes across breakpoints**
- **Only add breakpoint variants when values change**
```html
<!-- ❌ Redundant breakpoint classes -->
<div class="px-4 md:px-4 lg:px-4">
<!-- md:px-4 and lg:px-4 are redundant -->
</div>
<!-- ✅ Efficient breakpoint usage -->
<div class="px-4 lg:px-8">
<!-- Only specify when value changes -->
</div>
```
## Dark Mode
### Dark Mode Best Practices
- Use the plain `dark:` variant pattern
- Put light mode styles first, then dark mode styles
- Ensure `dark:` variant comes before other variants
```html
<!-- ✅ Correct dark mode pattern -->
<div class="bg-white text-black dark:bg-black dark:text-white">
<button class="hover:bg-gray-100 dark:hover:bg-gray-800">Click me</button>
</div>
```
## Gradient Utilities
- **Use `bg-linear-*` instead of `bg-gradient-*` utilities** - The gradient utilities were renamed in v4
- Use the new `bg-radial` or `bg-radial-[<position>]` to create radial gradients
- Use the new `bg-conic` or `bg-conic-*` to create conic gradients
```html
<!-- ✅ Use the new gradient utilities -->
<div class="h-14 bg-linear-to-br from-violet-500 to-fuchsia-500"></div>
<div class="size-18 bg-radial-[at_50%_75%] from-sky-200 via-blue-400 to-indigo-900 to-90%"></div>
<div class="size-24 bg-conic-180 from-indigo-600 via-indigo-50 to-indigo-600"></div>
<!-- ❌ Do not use bg-gradient-* utilities -->
<div class="h-14 bg-gradient-to-br from-violet-500 to-fuchsia-500"></div>
```
## Working with CSS Variables
### Accessing Theme Values
Tailwind CSS v4 exposes all theme values as CSS variables:
```css
/* Access colors, and other theme values */
.custom-element {
background: var(--color-red-500);
border-radius: var(--radius-lg);
}
```
### The `--spacing()` Function
Use the dedicated `--spacing()` function for spacing calculations:
```css
.custom-class {
margin-top: calc(100vh - --spacing(16));
}
```
### Extending theme values
Use CSS to extend theme values:
```css
@import "tailwindcss";
@theme {
--color-mint-500: oklch(0.72 0.11 178);
}
```
```html
<div class="bg-mint-500">
<!-- ... -->
</div>
```
## New v4 Features
### Container Queries
Use the `@container` class and size variants:
```html
<article class="@container">
<div class="flex flex-col @md:flex-row @lg:gap-8">
<img class="w-full @md:w-48" />
<div class="mt-4 @md:mt-0">
<!-- Content adapts to container size -->
</div>
</div>
</article>
```
### Container Query Units
Use container-based units like `cqw` for responsive sizing:
```html
<div class="@container">
<h1 class="text-[50cqw]">Responsive to container width</h1>
</div>
```
### Text Shadows (v4.1)
Use `text-shadow-*` utilities from `text-shadow-2xs` to `text-shadow-lg`:
```html
<!-- ✅ Text shadow examples -->
<h1 class="text-shadow-lg">Large shadow</h1>
<p class="text-shadow-sm/50">Small shadow with opacity</p>
```
### Masking (v4.1)
Use the new composable mask utilities for image and gradient masks:
```html
<!-- ✅ Linear gradient masks on specific sides -->
<div class="mask-t-from-50%">Top fade</div>
<div class="mask-b-from-20% mask-b-to-80%">Bottom gradient</div>
<div class="mask-linear-from-white mask-linear-to-black/60">Fade from white to black</div>
<!-- ✅ Radial gradient masks -->
<div class="mask-radial-[100%_100%] mask-radial-from-75% mask-radial-at-left">Radial mask</div>
```
### Font Feature Settings (v4.2)
Use `font-features-*` for low-level OpenType font features via `font-feature-settings`:
```html
<!-- ✅ Slashed zero — distinguish 0 from O (useful for addresses/hashes) -->
<span class="font-features-zero">0x1a2B3c</span>
<!-- ✅ Stylistic sets (font-dependent) -->
<span class="font-features-ss01">Alternative glyphs</span>
<!-- ✅ Multiple features -->
<span class="font-features-zero font-features-ss01">Combined features</span>
```
**When to use `font-features-*` vs high-level properties:**
- **Prefer `tabular-nums`** over `font-features-tnum` — `font-variant-numeric` is the high-level CSS property and doesn't conflict with other numeric features
- **Use `font-features-*`** for OpenType features that lack high-level CSS equivalents: stylistic sets (`ss01`–`ss20`), character variants (`cv01`–`cv99`), capital spacing (`cpsp`), case-sensitive forms (`case`)
- **`font-features-zero`** (slashed zero) overlaps with the `slashed-zero` utility but can be combined with other `font-features-*` values
## Component Patterns
### Avoiding Utility Inheritance
Don't add utilities to parents that you override in children:
```html
<!-- ❌ Avoid this pattern -->
<div class="text-center">
<h1>Centered Heading</h1>
<div class="text-left">Left-aligned content</div>
</div>
<!-- ✅ Better approach -->
<div>
<h1 class="text-center">Centered Heading</h1>
<div>Left-aligned content</div>
</div>
```
### Component Extraction
- Extract repeated patterns into framework components, not CSS classes
- Keep utility classes in templates/JSX
- Use data attributes for complex state-based styling
## CSS Best Practices
### Nesting Guidelines
- Use nesting when styling both parent and children
- Avoid empty parent selectors
```css
/* ✅ Good nesting - parent has styles */
.card {
padding: --spacing(4);
> .card-title {
font-weight: bold;
}
}
/* ❌ Avoid empty parents */
ul {
> li {
/* Parent has no styles */
}
}
```
## Common Pitfalls to Avoid
1. **Using old opacity utilities** - Always use `/opacity` syntax like `bg-red-500/60`
2. **Redundant breakpoint classes** - Only specify changes
3. **Space utilities in flex/grid** - Always use gap
4. **Leading utilities** - Use line-height modifiers like `text-sm/6`
5. **Arbitrary values** - Use the design scale
6. **@apply directive** - Use components or CSS variables
7. **min-h-screen on mobile** - Use min-h-dvh
8. **Separate width/height** - Use size utilities when equal
9. **Arbitrary values** - Always use Tailwind's predefined scale whenever possible (e.g., use `ml-4` over `ml-[16px]`)
```
### references/tw-animate-css.md
```markdown
# tw-animate-css Reference
Tailwind CSS v4 compatible animation library.
**Package:** `tw-animate-css` ([npm](https://www.npmjs.com/package/tw-animate-css) | [GitHub](https://github.com/Wombosvideo/tw-animate-css))
## Setup
Import in the project's main CSS file:
```css
@import "tw-animate-css";
```
## Animation Base Classes
Enter/exit animations require a base class:
| Base Class | Purpose |
| ------------- | ---------------------- |
| `animate-in` | Enable enter animation |
| `animate-out` | Enable exit animation |
## Animation Utilities
### Fade
| Class | Effect |
| ---------- | --------------- |
| `fade-in` | Fade in (enter) |
| `fade-out` | Fade out (exit) |
### Zoom
| Class | Effect |
| ---------- | --------------- |
| `zoom-in` | Zoom in (enter) |
| `zoom-out` | Zoom out (exit) |
### Spin
| Class | Effect |
| ---------- | --------------- |
| `spin-in` | Spin in (enter) |
| `spin-out` | Spin out (exit) |
### Slide
Slide utilities accept a direction and distance value.
**Directions:**
- `in-from-top`, `in-from-bottom`, `in-from-left`, `in-from-right`
- `out-to-top`, `out-to-bottom`, `out-to-left`, `out-to-right`
**Value Types:**
| Type | Example | Notes |
| ----------------- | --------------------------------- | ---------------------------------- |
| Integer spacing | `slide-in-from-bottom-4` | Uses Tailwind spacing scale (1-96) |
| Arbitrary length | `slide-in-from-bottom-[0.625rem]` | Any CSS length value |
| Arbitrary percent | `slide-in-from-bottom-[10%]` | Percentage of element |
**Spacing Scale Gotcha:**
Decimal spacing values like `2.5` are NOT supported directly:
```html
<!-- ❌ Invalid: decimal spacing not recognized -->
<div class="slide-in-from-bottom-2.5 animate-in">
<!-- ✅ Valid: use arbitrary value instead -->
<div class="slide-in-from-bottom-[0.625rem] animate-in">
<!-- ✅ Valid: use integer spacing -->
<div class="slide-in-from-bottom-2 animate-in">
```
**Spacing to rem conversion:** `value × 0.25rem`
- `2` = `0.5rem` (8px)
- `2.5` = `0.625rem` (10px) → use `[0.625rem]`
- `3` = `0.75rem` (12px)
## Duration and Timing
Control animation timing with standard Tailwind utilities:
| Utility | Purpose |
| -------------- | ------------------ |
| `duration-150` | Animation duration |
| `delay-100` | Animation delay |
| `ease-in` | Timing function |
| `ease-out` | Timing function |
| `ease-in-out` | Timing function |
## Fill Mode
Control element visibility after animation:
| Class | Effect |
| --------------------- | ------------------------------ |
| `fill-mode-none` | No fill mode |
| `fill-mode-forwards` | Keep end state |
| `fill-mode-backwards` | Apply start state immediately |
| `fill-mode-both` | Combine forwards and backwards |
## Common Patterns
### Enter Animation
```html
<div class="fade-in slide-in-from-bottom-4 duration-300 animate-in">
Content slides up and fades in
</div>
```
### Exit Animation
```html
<div class="fade-out slide-out-to-bottom-4 duration-200 animate-out">
Content slides down and fades out
</div>
```
### Responsive Animation
```html
<div class="lg:fade-in lg:slide-in-from-bottom-[0.625rem] lg:animate-in">
Only animates on lg+ breakpoints
</div>
```
### Combined Animation
```html
<div class="fade-in zoom-in-50 slide-in-from-bottom-8 duration-500 animate-in">
Multiple effects combined
</div>
```
## Quick Reference
| Want to... | Use |
| ------------------------------ | ----------------------------------- |
| Fade in | `fade-in animate-in` |
| Slide up on enter | `slide-in-from-bottom-4 animate-in` |
| Slide down on exit | `slide-out-to-bottom-4 animate-out` |
| Use decimal spacing (e.g. 2.5) | `slide-in-from-bottom-[0.625rem]` |
| Control duration | `duration-300` |
| Add delay | `delay-150` |
| Keep end state | `fill-mode-forwards` |
```