tailwind
SKILL.md
Tailwind CSS - Utility-First Styling
Patterns for Tailwind CSS v4, responsive design, and component composition
When to Use This Skill
Use this skill when:
- Styling applications with Tailwind CSS
- Building responsive layouts
- Creating reusable UI components
- Configuring Tailwind themes
- Implementing dark mode
- Optimizing for production
Don't use this skill when:
- Using CSS-in-JS libraries (styled-components, Emotion)
- Writing traditional CSS/SCSS
- Using other utility frameworks (UnoCSS, Windi)
Critical Patterns
Pattern 1: Responsive Design
When: Building mobile-first responsive layouts
// ✅ GOOD: Mobile-first responsive design
<div className="
flex flex-col gap-4
md:flex-row md:gap-6
lg:gap-8
">
{/* Stack on mobile, row on md+, larger gap on lg+ */}
<aside className="w-full md:w-64 lg:w-80">
<Sidebar />
</aside>
<main className="flex-1">
<Content />
</main>
</div>
// ✅ GOOD: Responsive typography
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold">
Responsive Heading
</h1>
// ✅ GOOD: Responsive grid
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-4">
{products.map(p => <ProductCard key={p.id} product={p} />)}
</div>
// ❌ BAD: Desktop-first (harder to maintain)
<div className="flex-row md:flex-col"> {/* Confusing! */}
Breakpoints (Tailwind defaults):
sm: 640pxmd: 768pxlg: 1024pxxl: 1280px2xl: 1536px
Pattern 2: Component Composition with CVA
When: Building variant-based components
// ✅ GOOD: Using class-variance-authority (CVA)
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';
const buttonVariants = cva(
// Base styles
'inline-flex items-center justify-center rounded-md font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50',
{
variants: {
variant: {
default: 'bg-primary text-primary-foreground hover:bg-primary/90',
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
},
size: {
default: 'h-10 px-4 py-2',
sm: 'h-9 px-3 text-sm',
lg: 'h-11 px-8 text-lg',
icon: 'h-10 w-10',
},
},
defaultVariants: {
variant: 'default',
size: 'default',
},
}
);
interface ButtonProps
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
VariantProps<typeof buttonVariants> {}
export function Button({ className, variant, size, ...props }: ButtonProps) {
return (
<button
className={cn(buttonVariants({ variant, size, className }))}
{...props}
/>
);
}
// Usage
<Button variant="destructive" size="lg">Delete</Button>
<Button variant="outline">Cancel</Button>
// ❌ BAD: Prop-based conditional classes without system
<button className={`
px-4 py-2 rounded
${variant === 'primary' ? 'bg-blue-500' : ''}
${variant === 'secondary' ? 'bg-gray-500' : ''}
${size === 'large' ? 'text-lg px-6' : ''}
`}>
Pattern 3: Dark Mode
When: Implementing light/dark themes
// ✅ GOOD: Class-based dark mode (recommended)
// tailwind.config.ts
export default {
darkMode: 'class', // or 'media' for system preference
// ...
}
// Component with dark mode support
<div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
<h1 className="text-2xl font-bold">Dashboard</h1>
<p className="text-gray-600 dark:text-gray-400">
Welcome back
</p>
</div>
// ✅ GOOD: CSS variables for theming
// globals.css
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--primary: 210 40% 98%;
}
}
// tailwind.config.ts
theme: {
extend: {
colors: {
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
primary: 'hsl(var(--primary))',
},
},
}
// Usage - automatically adapts to theme
<div className="bg-background text-foreground">
<button className="bg-primary text-primary-foreground">Click</button>
</div>
// ❌ BAD: Hardcoded colors without dark mode
<div className="bg-white text-black"> {/* No dark mode! */}
Pattern 4: Utility Function for Class Merging
When: Combining conditional classes safely
// ✅ GOOD: cn() utility with tailwind-merge
// lib/utils.ts
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
// Usage - handles conflicts correctly
<div className={cn(
'px-4 py-2 rounded',
isActive && 'bg-blue-500',
className // Allow override from props
)}>
// twMerge resolves conflicts:
cn('px-4', 'px-6') // → 'px-6' (not 'px-4 px-6')
cn('text-red-500', 'text-blue-500') // → 'text-blue-500'
// ❌ BAD: String concatenation (doesn't resolve conflicts)
className={`px-4 ${className}`} // px-4 and px-6 would both apply!
// ❌ BAD: Just clsx without twMerge
clsx('px-4', 'px-6') // → 'px-4 px-6' (both apply, undefined behavior)
Pattern 5: Layout Patterns
When: Building common layout structures
// ✅ GOOD: Centered container with max-width
<div className="container mx-auto px-4 sm:px-6 lg:px-8">
<Content />
</div>
// ✅ GOOD: Sticky header with content scroll
<div className="flex h-screen flex-col">
<header className="sticky top-0 z-50 border-b bg-background/95 backdrop-blur">
<Nav />
</header>
<main className="flex-1 overflow-auto">
<Content />
</main>
<footer className="border-t">
<Footer />
</footer>
</div>
// ✅ GOOD: Sidebar layout
<div className="flex h-screen">
<aside className="w-64 border-r bg-muted/50 overflow-y-auto">
<Sidebar />
</aside>
<main className="flex-1 overflow-y-auto">
<Content />
</main>
</div>
// ✅ GOOD: Card grid with equal heights
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{items.map(item => (
<div key={item.id} className="flex flex-col rounded-lg border p-6">
<h3 className="text-lg font-semibold">{item.title}</h3>
<p className="flex-1 text-muted-foreground">{item.description}</p>
<button className="mt-4">Learn more</button>
</div>
))}
</div>
Code Examples
Example 1: Form Styling
export function LoginForm() {
return (
<form className="space-y-4 w-full max-w-sm">
<div className="space-y-2">
<label htmlFor="email" className="text-sm font-medium">
Email
</label>
<input
id="email"
type="email"
className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50"
placeholder="you@example.com"
/>
</div>
<div className="space-y-2">
<label htmlFor="password" className="text-sm font-medium">
Password
</label>
<input
id="password"
type="password"
className="w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
/>
</div>
<button
type="submit"
className="w-full rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2"
>
Sign in
</button>
</form>
);
}
Example 2: Responsive Navigation
export function Navigation() {
const [isOpen, setIsOpen] = useState(false);
return (
<nav className="border-b">
<div className="container mx-auto flex h-16 items-center justify-between px-4">
<Logo />
{/* Desktop nav */}
<div className="hidden md:flex items-center gap-6">
<NavLink href="/products">Products</NavLink>
<NavLink href="/about">About</NavLink>
<NavLink href="/contact">Contact</NavLink>
<Button>Sign in</Button>
</div>
{/* Mobile menu button */}
<button
className="md:hidden p-2"
onClick={() => setIsOpen(!isOpen)}
aria-label="Toggle menu"
>
<MenuIcon className="h-6 w-6" />
</button>
</div>
{/* Mobile nav */}
{isOpen && (
<div className="md:hidden border-t p-4 space-y-4">
<NavLink href="/products" className="block">Products</NavLink>
<NavLink href="/about" className="block">About</NavLink>
<NavLink href="/contact" className="block">Contact</NavLink>
<Button className="w-full">Sign in</Button>
</div>
)}
</nav>
);
}
Example 3: Animation with Tailwind
// Hover and focus animations
<button className="transform transition-all duration-200 hover:scale-105 hover:shadow-lg active:scale-95">
Animated Button
</button>
// Fade in on mount (with Tailwind + React)
<div className="animate-in fade-in duration-500">
Content fades in
</div>
// Custom animation in config
// tailwind.config.ts
theme: {
extend: {
keyframes: {
'slide-in': {
'0%': { transform: 'translateX(-100%)' },
'100%': { transform: 'translateX(0)' },
},
},
animation: {
'slide-in': 'slide-in 0.3s ease-out',
},
},
}
// Usage
<div className="animate-slide-in">Slides in from left</div>
Anti-Patterns
Don't: Duplicate Class Strings
// ❌ BAD: Copy-pasting the same classes
<button className="px-4 py-2 rounded bg-blue-500 text-white hover:bg-blue-600">Save</button>
<button className="px-4 py-2 rounded bg-blue-500 text-white hover:bg-blue-600">Submit</button>
<button className="px-4 py-2 rounded bg-blue-500 text-white hover:bg-blue-600">Send</button>
// ✅ GOOD: Extract to component or CVA
const Button = ({ children }) => (
<button className="px-4 py-2 rounded bg-blue-500 text-white hover:bg-blue-600">
{children}
</button>
);
Don't: Over-customize in Config
// ❌ BAD: Adding every possible value
theme: {
extend: {
spacing: {
'13': '3.25rem',
'15': '3.75rem',
'17': '4.25rem',
// ...endless custom values
},
},
}
// ✅ GOOD: Use arbitrary values when needed
<div className="mt-[3.25rem]">Arbitrary value</div>
// Or stick to the default scale
<div className="mt-12 lg:mt-16">Uses default scale</div>
Don't: Ignore Accessibility
// ❌ BAD: Low contrast, no focus states
<button className="bg-gray-200 text-gray-400">Hard to read</button>
// ✅ GOOD: Proper contrast and focus states
<button className="bg-gray-900 text-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2">
Accessible
</button>
Quick Reference
| Task | Classes | Example |
|---|---|---|
| Center content | flex items-center justify-center |
Container centering |
| Responsive hide | hidden md:block |
Show only on md+ |
| Truncate text | truncate |
Single line ellipsis |
| Aspect ratio | aspect-video |
16:9 ratio |
| Gradient | bg-gradient-to-r from-blue-500 to-purple-500 |
Horizontal gradient |
| Shadow | shadow-md hover:shadow-lg |
Elevation effect |
| Ring focus | focus:ring-2 focus:ring-offset-2 |
Focus indicator |
Resources
Official Documentation:
Related Skills:
- react: React component patterns
- accessibility: WCAG compliance
- ui-ux: Design principles
Keywords
tailwind, tailwindcss, css, styling, responsive, utility-first, dark-mode, components, design-system
Weekly Installs
3
Repository
dsantiagomj/dsm…-toolkitFirst Seen
Feb 22, 2026
Security Audits
Installed on
gemini-cli3
github-copilot3
codex3
kimi-cli3
amp3
cursor3