Tailwind CSS
"Tailwind CSS: utility-first CSS, responsive design, dark mode, custom theme, plugins, @apply, JIT, content configuration, arbitrary values"
Tailwind CSS is a utility-first CSS framework that provides low-level utility classes to build custom designs directly in markup. Instead of writing custom CSS, you compose styles by combining small, single-purpose classes. The JIT (Just-In-Time) engine generates only the CSS you actually use, producing tiny production bundles. Tailwind encourages co-locating style decisions with markup, eliminating the mental overhead of naming CSS classes and the risk of dead CSS accumulating over time.
## Key Points
2. **Keep utility strings readable.** Group related utilities logically (layout, spacing, typography, color, state) and break long class lists across multiple lines.
3. **Leverage design tokens via @theme.** Define colors, spacing scales, and fonts in @theme to maintain consistency and enable theming.
4. **Use responsive prefixes mobile-first.** Start with the smallest screen and layer on `sm:`, `md:`, `lg:` overrides for larger viewports.
5. **Prefer semantic color names.** Use `text-brand` rather than `text-blue-500` so the palette can change in one place.
6. **Use `clsx` or `cva` for conditional classes.** Avoid string concatenation for variant logic; use a utility library for clarity and correctness.
7. **Purge unused CSS in production.** Ensure content paths are correctly configured so the JIT engine can tree-shake unused utilities.
1. **Overusing @apply to recreate BEM.** This defeats the purpose of utility-first CSS and reintroduces the naming and dead-CSS problems Tailwind eliminates.
2. **Inline style objects alongside Tailwind classes.** Mixing `style={{ marginTop: 12 }}` with className utilities creates two competing style systems and makes maintenance harder.
3. **Hardcoding pixel values everywhere.** Using `w-[347px]` instead of the spacing scale or a responsive unit leads to brittle layouts that break at different viewports.
4. **Ignoring dark mode from the start.** Retrofitting dark mode is painful; always add `dark:` variants alongside their light counterparts.
5. **Applying state variants to parent and child redundantly.** Use the `group-hover:` and `peer-*:` utilities to derive child state from a parent rather than duplicating hover listeners.
## Quick Example
```bash
npm install -D tailwindcss @tailwindcss/postcss postcss
```
```css
@import "tailwindcss";
@source "../components/**/*.{ts,tsx}";
@source "../lib/**/*.{ts,tsx}";
```skilldb get css-styling-services-skills/Tailwind CSSFull skill: 250 linesTailwind CSS
Core Philosophy
Tailwind CSS is a utility-first CSS framework that provides low-level utility classes to build custom designs directly in markup. Instead of writing custom CSS, you compose styles by combining small, single-purpose classes. The JIT (Just-In-Time) engine generates only the CSS you actually use, producing tiny production bundles. Tailwind encourages co-locating style decisions with markup, eliminating the mental overhead of naming CSS classes and the risk of dead CSS accumulating over time.
Setup
Installation with Next.js / React + Vite
npm install -D tailwindcss @tailwindcss/postcss postcss
PostCSS Configuration
// postcss.config.js
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};
CSS Entry Point
/* app/globals.css */
@import "tailwindcss";
/* Custom theme overrides */
@theme {
--color-brand: #3b82f6;
--color-brand-dark: #1d4ed8;
--font-family-display: "Inter", sans-serif;
}
Content Configuration
Tailwind v4 automatically detects your source files. For explicit control, use the @source directive:
@import "tailwindcss";
@source "../components/**/*.{ts,tsx}";
@source "../lib/**/*.{ts,tsx}";
Key Techniques
Responsive Design with Mobile-First Breakpoints
function ProductCard({ product }: { product: Product }) {
return (
<div className="w-full p-4 sm:w-1/2 md:w-1/3 lg:w-1/4">
<div className="rounded-lg border border-gray-200 bg-white shadow-sm
transition-shadow hover:shadow-md">
<img
src={product.image}
alt={product.name}
className="h-48 w-full rounded-t-lg object-cover sm:h-56 lg:h-64"
/>
<div className="p-4 sm:p-6">
<h3 className="text-lg font-semibold text-gray-900 sm:text-xl">
{product.name}
</h3>
<p className="mt-1 text-sm text-gray-500 line-clamp-2 sm:line-clamp-3">
{product.description}
</p>
<span className="mt-3 block text-xl font-bold text-brand">
${product.price}
</span>
</div>
</div>
</div>
);
}
Dark Mode
function SettingsPanel() {
return (
<section className="rounded-xl bg-white p-6 shadow dark:bg-gray-800 dark:shadow-gray-900/30">
<h2 className="text-xl font-bold text-gray-900 dark:text-gray-100">
Settings
</h2>
<p className="mt-2 text-gray-600 dark:text-gray-400">
Manage your preferences below.
</p>
<button
className="mt-4 rounded-lg bg-brand px-4 py-2 text-white
hover:bg-brand-dark
dark:bg-blue-500 dark:hover:bg-blue-400"
>
Save Changes
</button>
</section>
);
}
Arbitrary Values and Custom Properties
function HeroBanner() {
return (
<div className="relative h-[calc(100vh-4rem)] bg-[url('/hero.webp')]
bg-cover bg-[center_25%]">
<div className="absolute inset-0 bg-gradient-to-b from-black/60 to-black/20" />
<div className="relative z-10 flex h-full items-end pb-[clamp(2rem,8vw,6rem)]
px-[5vw]">
<h1 className="text-[clamp(2rem,5vw,4.5rem)] font-extrabold leading-tight
text-white drop-shadow-lg">
Build Something Great
</h1>
</div>
</div>
);
}
Extracting Components with @apply
/* Use sparingly — prefer component abstraction in React instead */
@layer components {
.btn-primary {
@apply inline-flex items-center justify-center rounded-lg bg-brand
px-5 py-2.5 text-sm font-medium text-white
transition-colors hover:bg-brand-dark
focus:outline-none focus:ring-2 focus:ring-brand/50
disabled:cursor-not-allowed disabled:opacity-50;
}
.input-field {
@apply block w-full rounded-lg border border-gray-300 bg-white
px-4 py-2.5 text-sm text-gray-900 placeholder-gray-400
focus:border-brand focus:ring-1 focus:ring-brand
dark:border-gray-600 dark:bg-gray-700 dark:text-white;
}
}
Custom Plugin
// tailwind-plugins/typography-utils.js
import plugin from "tailwindcss/plugin";
export const typographyUtils = plugin(({ addUtilities, theme }) => {
addUtilities({
".text-balance": {
"text-wrap": "balance",
},
".text-pretty": {
"text-wrap": "pretty",
},
".truncate-2": {
display: "-webkit-box",
"-webkit-line-clamp": "2",
"-webkit-box-orient": "vertical",
overflow: "hidden",
},
});
});
Conditional Classes with clsx
import { clsx } from "clsx";
interface BadgeProps {
variant: "success" | "warning" | "error" | "info";
children: React.ReactNode;
}
function Badge({ variant, children }: BadgeProps) {
return (
<span
className={clsx(
"inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium",
{
"bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-400":
variant === "success",
"bg-yellow-100 text-yellow-800 dark:bg-yellow-900/30 dark:text-yellow-400":
variant === "warning",
"bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400":
variant === "error",
"bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400":
variant === "info",
}
)}
>
{children}
</span>
);
}
Animation Utilities
function LoadingSpinner() {
return (
<div className="flex items-center gap-3">
<svg
className="h-5 w-5 animate-spin text-brand"
viewBox="0 0 24 24"
fill="none"
>
<circle className="opacity-25" cx="12" cy="12" r="10"
stroke="currentColor" strokeWidth="4" />
<path className="opacity-75" fill="currentColor"
d="M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" />
</svg>
<span className="animate-pulse text-sm text-gray-500">Loading...</span>
</div>
);
}
Best Practices
- Use the component pattern over @apply. Extract React components rather than creating @apply classes. The component already encapsulates markup and logic, so it is the natural place for style encapsulation too.
- Keep utility strings readable. Group related utilities logically (layout, spacing, typography, color, state) and break long class lists across multiple lines.
- Leverage design tokens via @theme. Define colors, spacing scales, and fonts in @theme to maintain consistency and enable theming.
- Use responsive prefixes mobile-first. Start with the smallest screen and layer on
sm:,md:,lg:overrides for larger viewports. - Prefer semantic color names. Use
text-brandrather thantext-blue-500so the palette can change in one place. - Use
clsxorcvafor conditional classes. Avoid string concatenation for variant logic; use a utility library for clarity and correctness. - Purge unused CSS in production. Ensure content paths are correctly configured so the JIT engine can tree-shake unused utilities.
Anti-Patterns
- Overusing @apply to recreate BEM. This defeats the purpose of utility-first CSS and reintroduces the naming and dead-CSS problems Tailwind eliminates.
- Inline style objects alongside Tailwind classes. Mixing
style={{ marginTop: 12 }}with className utilities creates two competing style systems and makes maintenance harder. - Hardcoding pixel values everywhere. Using
w-[347px]instead of the spacing scale or a responsive unit leads to brittle layouts that break at different viewports. - Ignoring dark mode from the start. Retrofitting dark mode is painful; always add
dark:variants alongside their light counterparts. - Applying state variants to parent and child redundantly. Use the
group-hover:andpeer-*:utilities to derive child state from a parent rather than duplicating hover listeners. - Neglecting accessibility. Utility classes make it easy to forget semantic HTML. Always pair visual styling with proper
aria-*attributes, focus rings (focus-visible:), and keyboard navigation.
Install this skill directly: skilldb add css-styling-services-skills
Related Skills
CSS Modules
"CSS Modules: scoped CSS, composition, global styles, Next.js integration, TypeScript declarations, naming conventions"
Lightning CSS
"Lightning CSS: ultra-fast CSS transformer, bundler, and minifier written in Rust, with modern syntax lowering, vendor prefixing, and CSS modules"
Panda CSS
"Panda CSS: build-time CSS-in-JS, atomic CSS, recipes, patterns, tokens, conditions, RSC compatible, type-safe styles"
Stitches
"Stitches: near-zero runtime CSS-in-JS, variants API, theme tokens, responsive styles, SSR support, polymorphic components"
Styled Components
"styled-components: CSS-in-JS, tagged template literals, theming, dynamic styles, SSR, global styles, extending"
UnoCSS
"UnoCSS: instant on-demand atomic CSS engine, presets, shortcuts, rules, variants, attributify mode, icon support, inspector"