
Tailwind Css
- 2.4k installs
- 68 repo stars
- Updated July 30, 2026
- paulrberg/agent-skills
tailwind-css is an agent skill that Use for Tailwind v4 styling: add/fix classes, configure or migrate Tailwind, use tailwind-variants, or tw-animate-css.
About
Expert guidance for Tailwind CSS v4 CSS first configuration modern utility patterns and type safe component styling with tailwind variants Tailwind CSS v4 eliminates tailwind config ts in favor of CSS only configuration All configuration lives in CSS files using special 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 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 The tailwind css agent skill provides documented workflows prerequisites triggers and safety guidance from its SKILL md source Agents load it when user requests match the description and follow step by step instructions without inventing capabilities It integrates with standard agent tooling for the tasks inputs outputs and failure modes described in
- description: 'Use for Tailwind v4 styling: add/fix classes, configure or migrate Tailwind, use tailwind-variants, or tw-
- Expert guidance for Tailwind CSS v4, CSS-first configuration, modern utility patterns, and type-safe component styling w
- Tailwind CSS v4 eliminates `tailwind.config.ts` in favor of CSS-only configuration. All configuration lives in CSS files
- Follow tailwind-css SKILL.md steps and documented constraints.
- Follow tailwind-css SKILL.md steps and documented constraints.
Tailwind Css by the numbers
- 2,386 all-time installs (skills.sh)
- +81 installs in the week ending Jul 29, 2026 (Skillselion tracking)
- Ranked #342 of 16,565 AI & Agent Building skills by installs in the Skillselion catalog
- Security screen: MEDIUM risk (skills.sh audit)
- Data as of Jul 31, 2026 (Skillselion catalog sync)
tailwind-css capabilities & compatibility
- Capabilities
- description: 'use for tailwind v4 styling: add/f · expert guidance for tailwind css v4, css first c · tailwind css v4 eliminates `tailwind.config.ts` · follow tailwind css skill.md steps and documente
- Use cases
- orchestration
What tailwind-css says it does
description: 'Use for Tailwind v4 styling: add/fix classes, configure or migrate Tailwind, use tailwind-variants, or tw-animate-css.'
Expert guidance for Tailwind CSS v4, CSS-first configuration, modern utility patterns, and type-safe component styling with tailwind-variants.
Tailwind CSS v4 eliminates `tailwind.config.ts` in favor of CSS-only configuration. All configuration lives in CSS files using special directives.
npx skills add https://github.com/paulrberg/agent-skills --skill tailwind-cssAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2.4k |
|---|---|
| repo stars | ★ 68 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 30, 2026 |
| Repository | paulrberg/agent-skills ↗ |
When should an agent use tailwind-css and what problem does it solve?
Use for Tailwind v4 styling: add/fix classes, configure or migrate Tailwind, use tailwind-variants, or tw-animate-css.
Who is it for?
Developers invoking tailwind-css as documented in the skill source.
Skip if: Skip when requirements fall outside tailwind-css documented scope.
When should I use this skill?
Use for Tailwind v4 styling: add/fix classes, configure or migrate Tailwind, use tailwind-variants, or tw-animate-css.
What you get
Outputs aligned with the tailwind-css SKILL.md workflow and stated deliverables.
- Corrected Tailwind utility class patterns in component code
Files
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:
@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 otherno-unknown-classes- Flag classes not registered with Tailwind
Stylistic Rules (warnings):
enforce-canonical-classes- Use standard v4 class namesenforce-shorthand-classes- Use abbreviated class versionsno-deprecated-classes- Remove outdated class namesno-duplicate-classes- Eliminate redundant declarationsno-unnecessary-whitespace- Clean up extra spacing
Examples:
// ❌ Bad: separate padding
<div className="px-6 py-6">
// ✅ Good: shorthand
<div className="p-6">// ❌ 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
For detailed coding patterns covering layout, spacing, typography, colors, borders, gradients, arbitrary values, class merging, image sizing, z-index, and dark mode, see references/coding-preferences.md.
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:
/* 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:
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:
// ✅ 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:
// 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
policy:
allow_implicit_invocation: true
Coding Preferences
When to read: when writing or fixing Tailwind utility class usage, layout, spacing, typography, color, border, gradient, arbitrary value, class-merging, image-sizing, z-index, or dark-mode patterns.
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.
// ✅ 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:**
// ✅ 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.
// ✅ 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.
// ✅ 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.
// ✅ 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:
// ✅ 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.
// ✅ 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.
// ✅ 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.
// ✅ 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-`:*
// ✅ 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 gradientsbg-conic- Conic gradients
Example:
<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.
// ✅ 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
classNameattributes:className="fixed classes"
Examples:
// ✅ 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.
// ✅ 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:
// ✅ 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:
@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.
// ✅ 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">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.
<!-- ❌ 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-
andspace-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
<!-- ❌ 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-screenis buggy on mobile Safari - *Prefer `size-
utilities** over separatew-` and `h-` when setting equal dimensions - For max-widths, prefer the container scale (e.g.,
max-w-2xsovermax-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
<!-- ❌ 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= 12pxtext-sm= 14pxtext-base= 16pxtext-lg= 18pxtext-xl= 20px
Color and Opacity
Opacity Modifiers
*Avoid `bg-opacity-, text-opacity-`, etc.* - use the opacity modifier syntax:
<!-- ❌ 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)
<!-- ✅ 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
<!-- ❌ 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
<!-- ✅ 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 ofbg-gradient-` utilities* - The gradient utilities were renamed in v4 - Use the new
bg-radialorbg-radial-[<position>]to create radial gradients - Use the new
bg-conicorbg-conic-*to create conic gradients
<!-- ✅ 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:
/* 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:
.custom-class {
margin-top: calc(100vh - --spacing(16));
}Extending theme values
Use CSS to extend theme values:
@import "tailwindcss";
@theme {
--color-mint-500: oklch(0.72 0.11 178);
}<div class="bg-mint-500">
<!-- ... -->
</div>New v4 Features
Container Queries
Use the @container class and size variants:
<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:
<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:
<!-- ✅ 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:
<!-- ✅ 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:
<!-- ✅ 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-numericis 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-zeroutility but can be combined with otherfont-features-*values
Component Patterns
Avoiding Utility Inheritance
Don't add utilities to parents that you override in children:
<!-- ❌ 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
/* ✅ 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])
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
bun add tailwind-variantsBuild Options:
// 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
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:
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:
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:
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:
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:
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:
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:
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:
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:
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:
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
const button = tv(
{
base: "rounded",
},
{
twMerge: true, // Enable tailwind-merge
twMergeConfig: {}, // Custom tailwind-merge config
}
);Global Configuration
import { defaultConfig } from "tailwind-variants";
defaultConfig.twMerge = false;Custom Instance with createTV
Create isolated configurations:
import { createTV } from "tailwind-variants";
const tv = createTV({
twMerge: true,
twMergeConfig: {
theme: {
colors: ["primary", "secondary"],
spacing: ["edge", "section"],
},
},
});Common Patterns
Button Component
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
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
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
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
twMergeis enabled andtailwind-mergeis installed - Check class specificity and order
- Verify Tailwind config includes component files
TypeScript errors:
- Use
as constfor external variant definitions - Use
VariantPropsto extract types - Verify all variant keys match between definition and usage
Conflict resolution issues:
- Use original build (not lite) for automatic merging
- Configure
twMergeConfigfor custom theme values - Ensure
tailwind-mergeis installed
tw-animate-css Reference
Tailwind CSS v4 compatible animation library.
Package: tw-animate-css (npm | GitHub)
Setup
Import in the project's main CSS file:
@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-rightout-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:
<!-- ❌ 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
<div class="fade-in slide-in-from-bottom-4 duration-300 animate-in">
Content slides up and fades in
</div>Exit Animation
<div class="fade-out slide-out-to-bottom-4 duration-200 animate-out">
Content slides down and fades out
</div>Responsive Animation
<div class="lg:fade-in lg:slide-in-from-bottom-[0.625rem] lg:animate-in">
Only animates on lg+ breakpoints
</div>Combined Animation
<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 |
Related skills
FAQ
What is tailwind-css?
Use for Tailwind v4 styling: add/fix classes, configure or migrate Tailwind, use tailwind-variants, or tw-animate-css.
When should I use tailwind-css?
Use for Tailwind v4 styling: add/fix classes, configure or migrate Tailwind, use tailwind-variants, or tw-animate-css.
Is tailwind-css safe to install?
Review the Security Audits panel on this page before production use.