tailwind-conventions
Tailwind CSS Conventions Skill
Consistent patterns for Tailwind CSS in React/Next.js applications.
Class Organization Order
Always organize classes in this order for readability:
className={cn(
// 1. Layout (position, display, flex/grid)
"relative flex flex-col",
// 2. Sizing (width, height, padding, margin)
"w-full max-w-md p-4 mx-auto",
// 3. Visual (background, border, shadow)
"bg-white border border-gray-200 rounded-lg shadow-sm",
// 4. Typography (font, text, color)
"text-sm font-medium text-gray-900",
// 5. States (hover, focus, active, disabled)
"hover:bg-gray-50 focus:ring-2 focus:ring-blue-500",
// 6. Responsive (sm:, md:, lg:, xl:)
"md:flex-row md:p-6",
// 7. Dark mode
"dark:bg-gray-800 dark:text-white"
)}
Utility Function (cn)
Use clsx + tailwind-merge for conditional classes:
// lib/utils.ts
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
// Usage
<div className={cn(
"base-classes",
isActive && "active-classes",
variant === "primary" && "primary-classes"
)} />
Responsive Design
Mobile-First Approach
// Start with mobile, add breakpoints for larger screens
<div className="
flex flex-col gap-2 // Mobile: stack vertically
md:flex-row md:gap-4 // Tablet+: horizontal row
lg:gap-6 // Desktop: more spacing
" />
Common Breakpoints
sm:- 640px+ (large phones)md:- 768px+ (tablets)lg:- 1024px+ (laptops)xl:- 1280px+ (desktops)2xl:- 1536px+ (large screens)
Responsive Typography
<h1 className="text-2xl md:text-3xl lg:text-4xl font-bold" />
<p className="text-sm md:text-base" />
Dark Mode
Using CSS Variables (Recommended)
/* globals.css */
:root {
--background: 255 255 255;
--foreground: 10 10 10;
}
.dark {
--background: 10 10 10;
--foreground: 255 255 255;
}
// tailwind.config.ts
theme: {
extend: {
colors: {
background: 'rgb(var(--background) / <alpha-value>)',
foreground: 'rgb(var(--foreground) / <alpha-value>)',
}
}
}
// Usage - no dark: prefix needed
<div className="bg-background text-foreground" />
Using dark: Prefix
<div className="
bg-white text-gray-900
dark:bg-gray-900 dark:text-white
" />
Component Patterns
Button Variants
const buttonVariants = {
base: "inline-flex items-center justify-center rounded-md font-medium transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none",
variants: {
primary: "bg-blue-600 text-white hover:bg-blue-700 focus:ring-blue-500",
secondary: "bg-gray-100 text-gray-900 hover:bg-gray-200 focus:ring-gray-500",
outline: "border border-gray-300 bg-transparent hover:bg-gray-50 focus:ring-gray-500",
ghost: "bg-transparent hover:bg-gray-100 focus:ring-gray-500",
destructive: "bg-red-600 text-white hover:bg-red-700 focus:ring-red-500",
},
sizes: {
sm: "h-8 px-3 text-sm",
md: "h-10 px-4 text-sm",
lg: "h-12 px-6 text-base",
}
};
Card Pattern
<div className="rounded-lg border border-gray-200 bg-white shadow-sm dark:border-gray-800 dark:bg-gray-950">
<div className="p-6">
<h3 className="text-lg font-semibold">Title</h3>
<p className="text-sm text-gray-500 dark:text-gray-400">Description</p>
</div>
</div>
Input Pattern
<input className="
flex h-10 w-full rounded-md border border-gray-300 bg-white px-3 py-2
text-sm placeholder:text-gray-400
focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent
disabled:cursor-not-allowed disabled:opacity-50
dark:border-gray-700 dark:bg-gray-900
" />
Spacing Conventions
Consistent Spacing Scale
gap-1/p-1= 4px (tight)gap-2/p-2= 8px (compact)gap-4/p-4= 16px (default)gap-6/p-6= 24px (comfortable)gap-8/p-8= 32px (spacious)
Container Pattern
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">
{/* Content */}
</div>
Animation
Transitions
// Smooth color/opacity transitions
<button className="transition-colors duration-200" />
// Transform transitions (scale, translate)
<div className="transition-transform duration-200 hover:scale-105" />
// All properties
<div className="transition-all duration-300" />
Built-in Animations
<div className="animate-spin" /> // Loading spinner
<div className="animate-pulse" /> // Skeleton loading
<div className="animate-bounce" /> // Attention grabber
<div className="animate-ping" /> // Notification dot
Accessibility
Focus States
// Always visible focus rings
<button className="
focus:outline-none
focus:ring-2
focus:ring-blue-500
focus:ring-offset-2
" />
// Focus-visible for keyboard only
<button className="
focus-visible:outline-none
focus-visible:ring-2
focus-visible:ring-blue-500
" />
Screen Reader
<span className="sr-only">Loading...</span> // Hidden visually, announced
<div aria-hidden="true" className="..." /> // Decorative, ignored
Layout Patterns
CSS Grid Layouts
// 12-column grid
<div className="grid grid-cols-12 gap-4">
<div className="col-span-8">Main content</div>
<div className="col-span-4">Sidebar</div>
</div>
// Auto-fit responsive grid
<div className="grid grid-cols-[repeat(auto-fit,minmax(300px,1fr))] gap-6">
{items.map(item => <Card key={item.id} />)}
</div>
// Dashboard grid
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
<StatCard />
<StatCard />
<StatCard />
<StatCard />
</div>
Sidebar Layout
// Fixed sidebar + scrollable content
<div className="flex h-screen">
<aside className="w-64 flex-shrink-0 border-r bg-gray-50 overflow-y-auto">
<nav className="p-4">{/* Nav items */}</nav>
</aside>
<main className="flex-1 overflow-y-auto p-6">
{/* Main content */}
</main>
</div>
// Collapsible sidebar
<div className="flex h-screen">
<aside className={cn(
"flex-shrink-0 border-r bg-gray-50 transition-all duration-300",
isOpen ? "w-64" : "w-16"
)}>
{/* Sidebar content */}
</aside>
<main className="flex-1">{/* Content */}</main>
</div>
Form Layouts
// Stacked form
<form className="space-y-4 max-w-md">
<div>
<label className="block text-sm font-medium mb-1">Email</label>
<input className="w-full rounded-md border px-3 py-2" />
</div>
<div>
<label className="block text-sm font-medium mb-1">Password</label>
<input className="w-full rounded-md border px-3 py-2" type="password" />
</div>
<button className="w-full bg-blue-600 text-white rounded-md py-2">
Sign In
</button>
</form>
// Inline form (search bar)
<form className="flex gap-2">
<input className="flex-1 rounded-md border px-3 py-2" placeholder="Search..." />
<button className="px-4 py-2 bg-blue-600 text-white rounded-md">Search</button>
</form>
// Two-column form
<form className="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<label className="block text-sm font-medium mb-1">First Name</label>
<input className="w-full rounded-md border px-3 py-2" />
</div>
<div>
<label className="block text-sm font-medium mb-1">Last Name</label>
<input className="w-full rounded-md border px-3 py-2" />
</div>
<div className="md:col-span-2">
<label className="block text-sm font-medium mb-1">Email</label>
<input className="w-full rounded-md border px-3 py-2" />
</div>
</form>
Header/Footer Layout
// Sticky header + footer
<div className="min-h-screen flex flex-col">
<header className="sticky top-0 z-50 border-b bg-white">
<nav className="mx-auto max-w-7xl px-4 h-16 flex items-center justify-between">
{/* Nav content */}
</nav>
</header>
<main className="flex-1">
{/* Page content */}
</main>
<footer className="border-t py-8">
{/* Footer content */}
</footer>
</div>
Centered Content
// Horizontally centered with max-width
<div className="mx-auto max-w-4xl px-4">{/* Content */}</div>
// Vertically and horizontally centered
<div className="min-h-screen flex items-center justify-center">
<div className="w-full max-w-md">{/* Centered card */}</div>
</div>
Anti-Patterns
- Don't use
@applyexcessively - defeats Tailwind's purpose - Don't create overly specific custom classes
- Don't fight the spacing scale - use what's provided
- Don't inline complex conditional logic - extract to variables
- Don't forget dark mode when adding colors
- Don't use arbitrary values
[123px]when scale values exist
Version
- v1.0.0 (2025-12-05): Added YAML frontmatter, initial documented version
More from benshapyro/cadre-devkit-claude
frontend-design
Create distinctive, memorable user interfaces that avoid generic AI aesthetics. Use when designing UI/UX, planning visual direction, or building pages and layouts.
10error-handler
Provides battle-tested error handling patterns for TypeScript and Python. Use when implementing error handling, creating try/catch blocks, or handling exceptions.
5react-patterns
Modern React patterns for TypeScript applications including hooks, state management, and component composition. Use when building React components, managing state, or implementing React best practices.
4product-discovery
Methodology for discovering and specifying new software products. Use when starting greenfield projects, exploring new ideas, or defining MVP scope.
4test-generator
Generates Jest or Pytest tests following Ben's testing standards. Use when creating tests, adding test coverage, writing unit tests, mocking dependencies, or when user mentions testing, test cases, Jest, Pytest, fixtures, assertions, or coverage.
3devkit-knowledge
Knowledge base for the Cadre DevKit. Use when answering questions about the devkit structure, commands, skills, hooks, agents, or workflows.
3