tailwind

Tailwind CSS v3 + v4 — utilities, custom configuration, design tokens, @theme directive, CSS-first config, native cascade layers, Lightning CSS engine, responsive design, plugin authoring, and component patterns. Absorbs tailwindcss, tailwind-v4.

inugamidev/ultrathink-oss2 installsMITSynced Aug 26

Works with

Claude CodeCursorCodex CLIGitHub CopilotGemini CLI
---
name: tailwind
description: Tailwind CSS v3 + v4 — utilities, custom configuration, design tokens, @theme directive, CSS-first config, native cascade layers, Lightning CSS engine, responsive design, plugin authoring, and component patterns. Absorbs tailwindcss, tailwind-v4.
license: MIT
---

# tailwind

Tailwind CSS v3 + v4 — utilities, custom configuration, design tokens, @theme directive, CSS-first config, native cascade layers, Lightning CSS engine, responsive design, plugin authoring, and component patterns. Absorbs tailwindcss, tailwind-v4.


## Absorbs

- `tailwindcss`
- `tailwind-v4`


---

## From `tailwindcss`

> Tailwind CSS utilities, custom configuration, design tokens, responsive design, and component styling patterns

# Tailwind CSS Patterns & Configuration

## Purpose

Provide expert guidance on Tailwind CSS v4+ utility-first styling, custom configuration, design token systems, responsive patterns, and maintainable component styling using class variance authority (CVA) and utility composition.

## Key Patterns

### Tailwind v4 CSS-First Configuration

Tailwind v4 moves configuration from `tailwind.config.ts` to CSS using `@theme`:

```css
/* app/globals.css */
@import "tailwindcss";

@theme {
  /* Colors using CSS custom properties */
  --color-brand-50: oklch(0.97 0.01 250);
  --color-brand-100: oklch(0.93 0.03 250);
  --color-brand-500: oklch(0.55 0.18 250);
  --color-brand-600: oklch(0.48 0.18 250);
  --color-brand-900: oklch(0.25 0.10 250);

  /* Semantic tokens */
  --color-surface: var(--color-brand-50);
  --color-surface-elevated: white;
  --color-text-primary: var(--color-brand-900);
  --color-text-secondary: oklch(0.45 0.03 250);
  --color-border: oklch(0.85 0.02 250);

  /* Typography scale (Golden Ratio) */
  --font-size-xs: 0.75rem;
  --font-size-sm: 0.875rem;
  --font-size-base: 1rem;
  --font-size-lg: 1.125rem;
  --font-size-xl: 1.25rem;
  --font-size-2xl: 1.625rem;
  --font-size-3xl: 2rem;
  --font-size-4xl: 2.625rem;
  --font-size-5xl: 4.25rem;

  /* Spacing scale */
  --spacing-xs: 0.25rem;
  --spacing-sm: 0.5rem;
  --spacing-md: 1rem;
  --spacing-lg: 1.5rem;
  --spacing-xl: 2rem;
  --spacing-2xl: 3rem;
  --spacing-3xl: 4rem;

  /* Radius */
  --radius-sm: 0.375rem;
  --radius-md: 0.5rem;
  --radius-lg: 0.75rem;
  --radius-xl: 1rem;
  --radius-full: 9999px;

  /* Shadows */
  --shadow-sm: 0 1px 2px 0 oklch(0 0 0 / 0.05);
  --shadow-md: 0 4px 6px -1px oklch(0 0 0 / 0.1), 0 2px 4px -2px oklch(0 0 0 / 0.1);
  --shadow-lg: 0 10px 15px -3px oklch(0 0 0 / 0.1), 0 4px 6px -4px oklch(0 0 0 / 0.1);

  /* Animations */
  --animate-fade-in: fade-in 0.2s ease-out;
  --animate-slide-up: slide-up 0.3s ease-out;
}

/* Dark mode tokens */
@media (prefers-color-scheme: dark) {
  @theme {
    --color-surface: oklch(0.15 0.02 250);
    --color-surface-elevated: oklch(0.20 0.02 250);
    --color-text-primary: oklch(0.95 0.01 250);
    --color-text-secondary: oklch(0.70 0.02 250);
    --color-border: oklch(0.30 0.02 250);
  }
}

@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes slide-up {
  from { opacity: 0; transform: translateY(0.5rem); }
  to { opacity: 1; transform: translateY(0); }
}
```

### Class Merging with `cn()`

Always use a `cn()` utility for conditional class merging:

```tsx
// lib/utils.ts
import { type ClassValue, clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

// Usage
<div className={cn(
  'p-6 rounded-xl shadow-sm transition-all duration-200',
  isActive && 'ring-2 ring-brand-500',
  className // allow parent override
)} />
```

### Component Variants with CVA

```tsx
// components/ui/button.tsx
import { cva, type VariantProps } from 'class-variance-authority';
import { cn } from '@/lib/utils';

const buttonVariants = cva(
  // Base styles (always applied)
  [
    'inline-flex items-center justify-center',
    'font-medium text-base rounded-lg',
    'transition-all duration-200',
    'focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none',
    'disabled:opacity-50 disabled:pointer-events-none',
    'motion-reduce:transition-none',
  ],
  {
    variants: {
      variant: {
        primary: 'bg-brand-600 text-white hover:bg-brand-700 focus-visible:ring-brand-500',
        secondary: 'bg-white border border-border text-text-primary hover:bg-gray-50 focus-visible:ring-brand-500',
        ghost: 'text-text-secondary hover:bg-gray-100 hover:text-text-primary',
        danger: 'bg-red-600 text-white hover:bg-red-700 focus-visible:ring-red-500',
      },
      size: {
        sm: 'px-4 py-2 text-sm min-h-[2rem]',
        md: 'px-6 py-4 text-base min-h-[2.625rem]',
        lg: 'px-8 py-4 text-lg min-h-[3rem]',
        icon: 'p-3 min-h-[2.625rem] min-w-[2.625rem]',
      },
    },
    defaultVariants: {
      variant: 'primary',
      size: 'md',
    },
  }
);

type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> &
  VariantProps<typeof buttonVariants> & {
    asChild?: boolean;
  };

export function Button({ className, variant, size, ...props }: ButtonProps) {
  return (
    <button
      className={cn(buttonVariants({ variant, size }), className)}
      {...props}
    />
  );
}

export { buttonVariants };
```

### Responsive Design

**Mobile-first breakpoints:**

```tsx
// Tailwind default breakpoints
// sm: 640px, md: 768px, lg: 1024px, xl: 1280px, 2xl: 1536px

// GOOD: Mobile-first, progressive enhancement
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
  {items.map(item => (
    <Card key={item.id} className="p-6 rounded-xl shadow-sm" />
  ))}
</div>

// Responsive typography
<h1 className="text-2xl sm:text-3xl lg:text-4xl font-bold">
  Responsive Heading
</h1>

// Responsive spacing
<section className="py-8 sm:py-12 lg:py-16 px-4 sm:px-6 lg:px-8">
  {/* Section content */}
</section>
```

**Container queries (v4):**

```tsx
// Parent declares containment
<div className="@container">
  {/* Children respond to parent width, not viewport */}
  <div className="grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-3 gap-4">
    {/* ... */}
  </div>
</div>
```

### Dark Mode

```tsx
// Class-based dark mode (recommended for toggle support)
// tailwind.config: darkMode: 'class'

<div className="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
  <div className="border border-gray-200 dark:border-gray-700 rounded-xl p-6 shadow-sm dark:shadow-none">
    <h2 className="text-xl font-semibold text-gray-900 dark:text-white">
      Card Title
    </h2>
    <p className="text-gray-600 dark:text-gray-400">
      Card description text.
    </p>
  </div>
</div>

// Prefer semantic tokens over explicit dark: variants
// With token system:
<div className="bg-surface text-text-primary border-border">
  {/* Automatically adapts to dark mode via CSS variables */}
</div>
```

### Layout Patterns

**Sticky Header:**

```tsx
<header className="sticky top-0 z-40 w-full border-b border-border bg-surface/80 backdrop-blur-sm">
  <div className="mx-auto max-w-7xl flex items-center justify-between px-4 sm:px-6 lg:px-8 h-16">
    {/* ... */}
  </div>
</header>
```

**Sidebar Layout:**

```tsx
<div className="flex min-h-screen">
  <aside className="hidden lg:flex lg:w-64 lg:flex-col border-r border-border">
    <nav className="flex-1 overflow-y-auto p-4">
      {/* Sidebar nav */}
    </nav>
  </aside>
  <main className="flex-1 overflow-y-auto">
    <div className="mx-auto max-w-5xl px-4 sm:px-6 lg:px-8 py-8">
      {/* Main content */}
    </div>
  </main>
</div>
```

**Center Content:**

```tsx
// Horizontal center with max-width
<div className="mx-auto max-w-2xl px-4 sm:px-6">

// Full center (e.g., login page)
<div className="min-h-screen flex items-center justify-center px-4">
  <div className="w-full max-w-md p-8 rounded-2xl shadow-lg">
    {/* Form */}
  </div>
</div>
```

### Animation Utilities

```tsx
// Entrance animation
<div className="animate-fade-in">Content</div>

// Hover effects
<div className="transition-all duration-200 hover:shadow-md hover:-translate-y-0.5">
  Card with lift effect
</div>

// Group hover
<div className="group p-6 rounded-xl shadow-sm transition-all duration-200 hover:shadow-md">
  <h3 className="font-semibold group-hover:text-brand-600 transition-colors duration-200">
    Title
  </h3>
  <span className="inline-flex items-center text-brand-600 opacity-0 group-hover:opacity-100 transition-opacity duration-200">
    Learn more &rarr;
  </span>
</div>

// Respect reduced motion
<div className="transition-all duration-200 motion-reduce:transition-none motion-reduce:hover:transform-none">
```

## Best Practices

1. **Mobile-first** — Always write base styles for mobile, then `sm:`, `md:`, `lg:` for larger screens.
2. **Use semantic tokens** — Define colors as semantic variables (`surface`, `text-primary`) not raw values.
3. **`cn()` for all conditional classes** — Never manually concatenate class strings.
4. **CVA for component variants** — Structured, type-safe variant management.
5. **Avoid `@apply` in v4** — Use component abstractions (React/Vue/Svelte) instead of `@apply` for reuse.
6. **Consistent spacing scale** — Use the defined spacing tokens, avoid arbitrary values like `p-[13px]`.
7. **Always add `transition-all duration-200`** on interactive elements.
8. **Include focus-visible states** — `focus-visible:ring-2 focus-visible:ring-offset-2` on all interactive elements.
9. **Respect `prefers-reduced-motion`** — Add `motion-reduce:transition-none` alongside transitions.
10. **Use `oklch` for colors** — Perceptually uniform, better for generating scales.

## Common Pitfalls

| Pitfall | Problem | Fix |
|---------|---------|-----|
| Arbitrary values everywhere | Inconsistent design, hard to maintain | Use design tokens and spacing scale |
| Missing dark mode | Unusable in dark environments | Use semantic tokens or explicit `dark:` variants |
| `@apply` overuse | Defeats utility-first purpose, bloats CSS | Use component abstractions for reuse |
| No `sr-only` for icon buttons | Inaccessible to screen readers | Add `<span className="sr-only">Label</span>` |
| Conflicting classes | `p-4 p-6` leads to unpredictable results | Use `cn()` with `tailwind-merge` |
| Missing responsive images | Layout shift, oversized images | Always set `w-full` and container sizing |
| Forgetting `min-h-screen` | Page shorter than viewport | Add to root layout container |
| Not using `group`/`peer` | Complex hover states require JavaScript | Use Tailwind's `group-hover:` and `peer-checked:` |
| No truncation on text | Long text breaks layout | Use `truncate` or `line-clamp-*` |
| Fixed widths on responsive layouts | Broken on different screens | Use `max-w-*` with `w-full` |


---

## From `tailwind-v4`

> Tailwind CSS v4 CSS-first configuration, @theme directive, cascade layers, Lightning CSS engine, and migration from v3

# Tailwind CSS v4 — CSS-First Configuration

## Purpose

Provide expert guidance on Tailwind CSS v4's paradigm shift to CSS-first configuration, replacing `tailwind.config.js` with native CSS directives. Covers the `@theme` directive, cascade layers, the Lightning CSS engine, custom utilities, and migration strategies from v3.

## Key Patterns

### CSS-First Configuration

**No more `tailwind.config.js`** — All configuration lives in CSS:

```css
/* app.css — the single entry point */
@import "tailwindcss";

@theme {
  --color-primary: #3b82f6;
  --color-primary-hover: #2563eb;
  --color-surface: #ffffff;
  --color-surface-alt: #f8fafc;

  --font-sans: "Inter", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", monospace;

  --radius-sm: 0.375rem;
  --radius-md: 0.5rem;
  --radius-lg: 0.75rem;
  --radius-xl: 1rem;

  --spacing-gutter: 1.5rem;
  --spacing-section: 4rem;
}
```

### The @theme Directive

**Define design tokens as CSS custom properties** — Tailwind v4 auto-generates utility classes from `@theme` variables:

```css
@theme {
  /* Colors: generates bg-brand, text-brand, border-brand, etc. */
  --color-brand: #6366f1;
  --color-brand-light: #818cf8;
  --color-brand-dark: #4f46e5;

  /* Spacing: generates p-18, m-18, gap-18, etc. */
  --spacing-18: 4.5rem;
  --spacing-22: 5.5rem;

  /* Font sizes: generates text-display, text-title, etc. */
  --font-size-display: 3rem;
  --font-size-title: 2rem;
  --line-height-display: 1.1;
  --line-height-title: 1.25;

  /* Breakpoints: generates sm:, md:, etc. */
  --breakpoint-xs: 30rem;
  --breakpoint-sm: 40rem;
  --breakpoint-md: 48rem;
  --breakpoint-lg: 64rem;
  --breakpoint-xl: 80rem;

  /* Animations: generates animate-fade-in, etc. */
  --animate-fade-in: fade-in 0.3s ease-out;
}

@keyframes fade-in {
  from { opacity: 0; transform: translateY(0.5rem); }
  to { opacity: 1; transform: translateY(0); }
}
```

### Cascade Layers

**Tailwind v4 uses native CSS cascade layers** for deterministic specificity:

```css
/* Layer order (lowest to highest priority):
   @layer theme, base, components, utilities; */

/* Override base styles */
@layer base {
  html {
    font-family: var(--font-sans);
    color: var(--color-foreground);
  }

  h1, h2, h3 {
    font-weight: 700;
    line-height: 1.2;
  }
}

/* Component-level styles */
@layer components {
  .btn-primary {
    @apply px-6 py-4 text-base font-medium rounded-lg
           bg-primary text-white
           transition-all duration-200
           hover:bg-primary-hover
           focus-visible:ring-2 focus-visible:ring-offset-2;
  }

  .card {
    @apply p-6 rounded-xl shadow-sm bg-surface;
  }
}

/* Custom utilities land here automatically */
@layer utilities {
  .text-balance {
    text-wrap: balance;
  }
}
```

### Custom Utilities and Variants

**Register custom utilities** directly in CSS:

```css
@utility text-shadow-sm {
  text-shadow: 0 1px 2px rgb(0 0 0 / 0.1);
}

@utility text-shadow-md {
  text-shadow: 0 2px 4px rgb(0 0 0 / 0.15);
}

@utility scrollbar-hidden {
  scrollbar-width: none;
  &::-webkit-scrollbar { display: none; }
}

/* Custom variant */
@variant hocus (&:hover, &:focus-visible);
@variant group-hocus (:merge(.group):hover &, :merge(.group):focus-visible &);
```

### Lightning CSS Engine

**Automatic transforms** — No PostCSS needed for most cases:

```css
/* Nesting works natively */
.nav {
  display: flex;
  gap: 1rem;

  & a {
    padding: 0.75rem 1rem;
    border-radius: var(--radius-md);
    transition: all 200ms;

    &:hover {
      background: var(--color-surface-alt);
    }
  }
}

/* Modern color functions auto-prefixed */
.element {
  color: oklch(0.7 0.15 250);
  background: color-mix(in oklch, var(--color-primary) 10%, transparent);
}
```

### Dark Mode with @theme

```css
@theme {
  --color-bg: #ffffff;
  --color-fg: #0f172a;
  --color-muted: #64748b;
  --color-surface: #ffffff;
  --color-border: #e2e8f0;
}

@theme dark {
  --color-bg: #0f172a;
  --color-fg: #f1f5f9;
  --color-muted: #94a3b8;
  --color-surface: #1e293b;
  --color-border: #334155;
}
```

### Migration from v3

**Before (v3 — `tailwind.config.js`):**

```js
// tailwind.config.js — DELETE THIS
module.exports = {
  theme: {
    extend: {
      colors: {
        brand: '#6366f1',
      },
      fontFamily: {
        sans: ['Inter', 'system-ui', 'sans-serif'],
      },
    },
  },
  plugins: [require('@tailwindcss/typography')],
};
```

**After (v4 — `app.css`):**

```css
@import "tailwindcss";
@plugin "@tailwindcss/typography";

@theme {
  --color-brand: #6366f1;
  --font-sans: "Inter", system-ui, sans-serif;
}
```

## Best Practices

1. **Single CSS entry point** — Keep one `app.css` with all `@theme`, `@layer`, and `@import` directives. Avoid scattering config across files.
2. **Use semantic token names** — Name colors by purpose (`--color-surface`, `--color-primary`) not appearance (`--color-blue`, `--color-light-gray`).
3. **Lean on cascade layers** — Put reusable component styles in `@layer components`. Utilities always win due to layer ordering.
4. **Migrate incrementally** — v4 supports a compatibility mode. Move one section of `tailwind.config.js` at a time into `@theme`.
5. **Leverage Lightning CSS** — Remove PostCSS plugins for nesting, autoprefixer, and color functions. Lightning CSS handles them natively.
6. **Use `@utility` for project-specific helpers** — Instead of arbitrary values like `[text-shadow:...]`, register a named utility.
7. **Keep `@theme` tokens flat** — Avoid deeply nested naming. `--color-primary` not `--color-brand-primary-default`.

## Common Pitfalls

| Pitfall | Problem | Fix |
|---------|---------|-----|
| Keeping `tailwind.config.js` alongside v4 CSS | Conflicting configuration sources | Migrate fully to CSS `@theme` or use compat mode explicitly |
| Wrong layer ordering | Component styles override utility classes | Never put component styles in `@layer utilities`; use `@layer components` |
| Using PostCSS nesting plugin | Conflicts with Lightning CSS built-in nesting | Remove `postcss-nesting` and `postcss-nested` plugins |
| `@apply` in `@layer utilities` | Circular reference when applying utilities inside utility layer | Use `@apply` only in `@layer components` or `@layer base` |
| Hardcoded values instead of tokens | Loses theme consistency and dark mode support | Reference `var(--color-*)` or use generated utility classes |
| Missing `@import "tailwindcss"` | No utility classes generated at all | Must be the first import in your CSS entry point |
| Ignoring `@theme dark` | Manual dark mode selectors everywhere | Define dark overrides in `@theme dark` block for automatic support |
| Prefixing custom properties wrong | `--tw-color-brand` does not generate classes | Use the exact namespace: `--color-*`, `--spacing-*`, `--font-size-*` |

More Design Systems skills

stitch-design-taste

leonxlnx/taste-skill

Semantic Design System Skill for Google Stitch. Generates agent-friendly DESIGN.md files that enforce premium, anti-generic UI standards — strict typography, calibrated color, asymmetric layouts, perpetual micro-motion, and hardware-accelerated performance.

265.6k

figma

heygen-com/hyperframes

Import Figma content into a HyperFrames composition — rendered assets, brand tokens, components, storyboard sections → reconstructed motion (frames read as states, not slides) (REST/CLI), connector-assisted motion when available, and shaders from a connector or native export. Use when the user pastes a figma.com link or asks to bring a Figma design, frame, logo, brand, or animation into a video/composition.

101.8k

image

coreyhaines31/marketingskills

When the user wants to create, generate, edit, or optimize images for marketing — blog heroes, social graphics, product mockups, profile banners, listing visuals, or brand assets. Also use when the user mentions 'AI image generation,' 'generate an image,' 'create a graphic,' 'product mockup,' 'hero image,' 'social media graphic,' 'banner image,' 'cover photo,' 'profile banner,' 'listing screenshot,' 'Flux,' 'Flux Kontext,' 'Midjourney,' 'DALL-E,' 'GPT Image,' 'ChatGPT Images,' 'Ideogram,' 'Gemini image,' 'Nano Banana,' 'Recraft,' 'Stable Diffusion,' 'Canva,' 'Figma,' 'image optimization,' 'compress images,' 'WebP,' or 'OG image.' Use this for general-purpose marketing image creation and optimization. For paid ad image creative and platform-specific ad specs, see ad-creative. For video production, see video.

62.9k

← All Design Systems skills

Check your AI visibility

One URL in, a 0–100 score and the exact fixes out.

RUN THE CHECK

Browse all the tools

15 tools across six categories
13 of them never send your data anywhere

Free · No signup · No trial clock

SEE THE DIRECTORY