Update Tailwind CSS configuration, custom themes, and design tokens across packages. Use when adding new colors, spacing scales, or customizing the design system.
Installation
Details
Usage
After installing, this skill will be available to your AI coding assistant.
Verify installation:
npx agent-skills-cli listSkill Instructions
name: tailwind-config description: Update Tailwind CSS configuration, custom themes, and design tokens across packages. Use when adding new colors, spacing scales, or customizing the design system. allowed-tools: Read, Edit, Grep, Glob
Tailwind CSS Configuration Skill
This skill helps you configure and customize Tailwind CSS across the monorepo.
When to Use This Skill
- Adding custom colors to the design system
- Configuring typography scales
- Customizing spacing and sizing
- Setting up design tokens
- Configuring Tailwind plugins
- Debugging Tailwind configuration issues
- Creating reusable theme presets
Tailwind Configuration Structure
βββ packages/ui/
β βββ tailwind.config.ts # UI package Tailwind config
β βββ src/styles/globals.css # Global styles and CSS variables
βββ apps/web/
βββ tailwind.config.ts # Web app Tailwind config
βββ src/app/globals.css # App-specific global styles
Base Tailwind Configuration
UI Package Configuration
// packages/ui/tailwind.config.ts
import type { Config } from "tailwindcss";
const config: Config = {
darkMode: ["class"],
content: [
"./src/**/*.{ts,tsx}",
],
theme: {
container: {
center: true,
padding: "2rem",
screens: {
"2xl": "1400px",
},
},
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
keyframes: {
"accordion-down": {
from: { height: "0" },
to: { height: "var(--radix-accordion-content-height)" },
},
"accordion-up": {
from: { height: "var(--radix-accordion-content-height)" },
to: { height: "0" },
},
},
animation: {
"accordion-down": "accordion-down 0.2s ease-out",
"accordion-up": "accordion-up 0.2s ease-out",
},
},
},
plugins: [require("tailwindcss-animate")],
};
export default config;
App Configuration (Extending UI)
// apps/web/tailwind.config.ts
import type { Config } from "tailwindcss";
import baseConfig from "@sgcarstrends/ui/tailwind.config";
const config: Config = {
...baseConfig,
content: [
"./src/**/*.{ts,tsx}",
"../../packages/ui/src/**/*.{ts,tsx}", // Include UI package components
],
theme: {
...baseConfig.theme,
extend: {
...(baseConfig.theme?.extend || {}),
// App-specific extensions
colors: {
...(baseConfig.theme?.extend?.colors || {}),
brand: {
50: "#f0f9ff",
100: "#e0f2fe",
200: "#bae6fd",
300: "#7dd3fc",
400: "#38bdf8",
500: "#0ea5e9",
600: "#0284c7",
700: "#0369a1",
800: "#075985",
900: "#0c4a6e",
},
},
},
},
};
export default config;
CSS Variables
Global Styles with CSS Variables
/* packages/ui/src/styles/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
}
}
Common Customizations
Adding Brand Colors
// tailwind.config.ts
export default {
theme: {
extend: {
colors: {
brand: {
primary: "#0070F3",
secondary: "#7928CA",
accent: "#FF0080",
},
// Singapore-themed colors
sg: {
red: "#ED2939",
white: "#FFFFFF",
},
},
},
},
};
Usage:
<div className="bg-brand-primary text-white">
<h1 className="text-brand-accent">SG Cars Trends</h1>
</div>
Custom Typography
// tailwind.config.ts
export default {
theme: {
extend: {
fontFamily: {
sans: ["Inter", "system-ui", "sans-serif"],
mono: ["Fira Code", "monospace"],
},
fontSize: {
"2xs": "0.625rem", // 10px
xs: "0.75rem", // 12px
sm: "0.875rem", // 14px
base: "1rem", // 16px
lg: "1.125rem", // 18px
xl: "1.25rem", // 20px
"2xl": "1.5rem", // 24px
"3xl": "1.875rem", // 30px
"4xl": "2.25rem", // 36px
"5xl": "3rem", // 48px
},
lineHeight: {
tight: "1.2",
normal: "1.5",
relaxed: "1.75",
},
},
},
};
Custom Spacing
// tailwind.config.ts
export default {
theme: {
extend: {
spacing: {
"4.5": "1.125rem", // 18px
"13": "3.25rem", // 52px
"15": "3.75rem", // 60px
"128": "32rem", // 512px
"144": "36rem", // 576px
},
},
},
};
Custom Breakpoints
// tailwind.config.ts
export default {
theme: {
screens: {
xs: "475px",
sm: "640px",
md: "768px",
lg: "1024px",
xl: "1280px",
"2xl": "1536px",
"3xl": "1920px",
},
},
};
Custom Animations
// tailwind.config.ts
export default {
theme: {
extend: {
keyframes: {
shimmer: {
"0%": { backgroundPosition: "-200% 0" },
"100%": { backgroundPosition: "200% 0" },
},
fadeIn: {
"0%": { opacity: "0" },
"100%": { opacity: "1" },
},
slideUp: {
"0%": { transform: "translateY(10px)", opacity: "0" },
"100%": { transform: "translateY(0)", opacity: "1" },
},
},
animation: {
shimmer: "shimmer 2s linear infinite",
fadeIn: "fadeIn 0.3s ease-out",
slideUp: "slideUp 0.4s ease-out",
},
},
},
};
Usage:
<div className="animate-shimmer bg-gradient-to-r from-gray-200 via-gray-300 to-gray-200">
Loading...
</div>
Tailwind Plugins
Typography Plugin
pnpm add -D @tailwindcss/typography
// tailwind.config.ts
export default {
plugins: [
require("@tailwindcss/typography"),
],
};
Usage:
<article className="prose lg:prose-xl dark:prose-invert">
<h1>Blog Post Title</h1>
<p>Content goes here...</p>
</article>
Forms Plugin
pnpm add -D @tailwindcss/forms
// tailwind.config.ts
export default {
plugins: [
require("@tailwindcss/forms"),
],
};
Container Queries Plugin
pnpm add -D @tailwindcss/container-queries
// tailwind.config.ts
export default {
plugins: [
require("@tailwindcss/container-queries"),
],
};
Usage:
<div className="@container">
<div className="@sm:grid @sm:grid-cols-2 @lg:grid-cols-3">
{/* Content */}
</div>
</div>
Custom Utilities
Adding Custom Utilities
/* packages/ui/src/styles/globals.css */
@layer utilities {
.text-balance {
text-wrap: balance;
}
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
.glass {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2);
}
}
Plugin-Based Custom Utilities
// tailwind.config.ts
import plugin from "tailwindcss/plugin";
export default {
plugins: [
plugin(function ({ addUtilities }) {
addUtilities({
".no-scrollbar": {
"-ms-overflow-style": "none",
"scrollbar-width": "none",
"&::-webkit-scrollbar": {
display: "none",
},
},
".scrollbar-thin": {
"scrollbar-width": "thin",
},
});
}),
],
};
Design Tokens
Creating a Shared Preset
// packages/ui/tailwind-preset.ts
import type { Config } from "tailwindcss";
const preset: Partial<Config> = {
darkMode: ["class"],
theme: {
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
popover: {
DEFAULT: "hsl(var(--popover))",
foreground: "hsl(var(--popover-foreground))",
},
card: {
DEFAULT: "hsl(var(--card))",
foreground: "hsl(var(--card-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
},
},
};
export default preset;
Use in apps:
// apps/web/tailwind.config.ts
import preset from "@sgcarstrends/ui/tailwind-preset";
export default {
presets: [preset],
content: ["./src/**/*.{ts,tsx}"],
theme: {
extend: {
// App-specific extensions
},
},
};
Dark Mode Configuration
Class-Based Dark Mode
// tailwind.config.ts
export default {
darkMode: ["class"],
};
Theme Toggle Implementation
"use client";
import { useTheme } from "next-themes";
import { Button } from "@sgcarstrends/ui";
export function ThemeToggle() {
const { theme, setTheme } = useTheme();
return (
<Button
variant="ghost"
size="icon"
onClick={() => setTheme(theme === "dark" ? "light" : "dark")}
>
{theme === "dark" ? "π" : "βοΈ"}
</Button>
);
}
Provider Setup
pnpm add next-themes
// app/providers.tsx
"use client";
import { ThemeProvider } from "next-themes";
export function Providers({ children }: { children: React.ReactNode }) {
return (
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
{children}
</ThemeProvider>
);
}
Responsive Design Patterns
Mobile-First Approach
// Default (mobile)
<div className="text-sm p-4">
{/* Mobile styles */}
</div>
// Tablet and up
<div className="text-sm md:text-base p-4 md:p-6">
{/* Tablet styles */}
</div>
// Desktop and up
<div className="text-sm md:text-base lg:text-lg p-4 md:p-6 lg:p-8">
{/* Desktop styles */}
</div>
Container Queries
<div className="@container">
<div className="grid grid-cols-1 @md:grid-cols-2 @lg:grid-cols-3 gap-4">
{/* Responsive grid based on container */}
</div>
</div>
Performance Optimization
Content Configuration
// tailwind.config.ts
export default {
content: [
"./src/**/*.{ts,tsx}",
// Only include what's needed
"../../packages/ui/src/**/*.{ts,tsx}",
],
// Safelist classes that are generated dynamically
safelist: [
"bg-red-500",
"bg-green-500",
"bg-blue-500",
],
};
Purge Unused Styles
Tailwind automatically purges unused styles in production. For dynamic classes:
// β Bad - Won't be detected
<div className={`bg-${color}-500`}>
// β
Good - Use safelist or full class names
<div className={color === 'red' ? 'bg-red-500' : 'bg-blue-500'}>
Debugging
Enable JIT Debug Mode
# See which classes are being generated
TAILWIND_MODE=watch npx tailwindcss -i ./src/styles/globals.css -o ./dist/output.css --watch
Check Configuration
# Inspect resolved config
npx tailwindcss config
Common Issues
Classes not applying:
- Check content paths include all component files
- Verify CSS is imported in app
- Check for typos in class names
- Ensure build process is running
Dark mode not working:
- Verify
darkMode: ["class"]in config - Check ThemeProvider is set up
- Ensure dark mode classes are in CSS
Purge removing needed classes:
- Add to safelist
- Use complete class names (not dynamic)
- Check content paths
Testing Tailwind Classes
// __tests__/components/button.test.tsx
import { render } from "@testing-library/react";
import { Button } from "@sgcarstrends/ui";
describe("Button Tailwind Classes", () => {
it("applies variant classes correctly", () => {
const { container } = render(<Button variant="destructive">Delete</Button>);
const button = container.querySelector("button");
// Check if destructive variant classes are applied
expect(button?.className).toContain("bg-destructive");
});
it("applies size classes correctly", () => {
const { container } = render(<Button size="lg">Large</Button>);
const button = container.querySelector("button");
expect(button?.className).toContain("h-11");
});
});
References
- Tailwind CSS Documentation: https://tailwindcss.com
- Related files:
packages/ui/tailwind.config.ts- UI package configapps/web/tailwind.config.ts- Web app configpackages/ui/src/styles/globals.css- Global stylespackages/ui/CLAUDE.md- UI package documentation
Best Practices
- Mobile-First: Design for mobile, then add larger breakpoints
- CSS Variables: Use CSS variables for theming
- Reusable Presets: Share configuration via presets
- Content Paths: Include all component paths
- Safelist Sparingly: Only safelist when absolutely necessary
- Semantic Names: Use meaningful color names (brand, accent, not blue-500)
- Dark Mode: Support dark mode from the start
- Performance: Minimize custom utilities, use Tailwind defaults
- Size Utility: Use
size-*instead ofh-* w-*when dimensions are equal (Tailwind v3.4+)
Size Utility Convention
When an element needs equal height and width, use the size-* utility instead of separate h-* and w-* classes:
// β
Good - Use size-* for equal dimensions
<div className="size-4">Icon</div>
<div className="size-8">Avatar</div>
<button className="size-10">Icon Button</button>
// β Avoid - Redundant h-* and w-*
<div className="h-4 w-4">Icon</div>
<div className="h-8 w-8">Avatar</div>
<button className="h-10 w-10">Icon Button</button>
// β
Good - Different dimensions still use h-* and w-*
<div className="h-4 w-6">Rectangle</div>
<div className="h-full w-32">Sidebar</div>
Common Use Cases:
- Icons:
size-4,size-5,size-6 - Avatars:
size-8,size-10,size-12 - Icon buttons:
size-8,size-10,size-12 - Loading spinners:
size-4,size-6,size-8 - Square containers:
size-16,size-24,size-32
More by NeverSight
View allAdvanced distributed event patterns for ABP microservices including idempotent handlers, cross-tenant events, event sourcing lite, and saga patterns. Use when: (1) implementing event handlers across services, (2) ensuring idempotent event processing, (3) cross-tenant event handling, (4) designing event-driven architectures.
Optimize decisions using proof-weighted scoring.
CLIP, SigLIP 2, Voyage multimodal-3 patterns for image+text retrieval, cross-modal search, and multimodal document chunking. Use when building RAG with images, implementing visual search, or hybrid retrieval.
knowledge-base-builder for learning content management and knowledge systems.
