tailwind

Tailwind CSS - Utility-First Styling

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "tailwind" with this command: npx skills add dsantiagomj/dsmj-ai-toolkit/dsantiagomj-dsmj-ai-toolkit-tailwind

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 : 640px

  • md : 768px

  • lg : 1024px

  • xl : 1280px

  • 2xl : 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>

  &#x3C;div className="space-y-2">
    &#x3C;label htmlFor="password" className="text-sm font-medium">
      Password
    &#x3C;/label>
    &#x3C;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"
    />
  &#x3C;/div>

  &#x3C;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
  &#x3C;/button>
&#x3C;/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 */}
    &#x3C;div className="hidden md:flex items-center gap-6">
      &#x3C;NavLink href="/products">Products&#x3C;/NavLink>
      &#x3C;NavLink href="/about">About&#x3C;/NavLink>
      &#x3C;NavLink href="/contact">Contact&#x3C;/NavLink>
      &#x3C;Button>Sign in&#x3C;/Button>
    &#x3C;/div>

    {/* Mobile menu button */}
    &#x3C;button
      className="md:hidden p-2"
      onClick={() => setIsOpen(!isOpen)}
      aria-label="Toggle menu"
    >
      &#x3C;MenuIcon className="h-6 w-6" />
    &#x3C;/button>
  &#x3C;/div>

  {/* Mobile nav */}
  {isOpen &#x26;&#x26; (
    &#x3C;div className="md:hidden border-t p-4 space-y-4">
      &#x3C;NavLink href="/products" className="block">Products&#x3C;/NavLink>
      &#x3C;NavLink href="/about" className="block">About&#x3C;/NavLink>
      &#x3C;NavLink href="/contact" className="block">Contact&#x3C;/NavLink>
      &#x3C;Button className="w-full">Sign in&#x3C;/Button>
    &#x3C;/div>
  )}
&#x3C;/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:

  • Tailwind CSS

  • Tailwind UI

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

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

patterns

No summary provided by upstream source.

Repository SourceNeeds Review
General

vercel-ai-sdk

No summary provided by upstream source.

Repository SourceNeeds Review
General

caching

No summary provided by upstream source.

Repository SourceNeeds Review
General

react

No summary provided by upstream source.

Repository SourceNeeds Review