From tailwind
Configures Tailwind CSS via tailwind.config.js, covering content paths, theme extensions like colors and fonts, plugins, safelists, dark mode, and build setup.
npx claudepluginhub thebushidocollective/han --plugin tailwindThis skill is limited to using the following tools:
Tailwind CSS is highly customizable through its configuration file, allowing you to define your design system, extend the default theme, and configure plugins.
Guides Tailwind CSS mastery: v3/v4 configuration, custom plugins, responsive design with breakpoints and container queries, dark mode via class strategy and semantic tokens, performance optimization, and CVA patterns.
Sets up Tailwind CSS with TypeScript in Next.js, Vite, or React projects. Covers installation, configuration, custom theme extensions, type-safe styling utilities, and plugins. Use when adding Tailwind to existing TS projects or customizing design systems.
Provides Tailwind CSS best practices for responsive design, dark mode, reusable components, configuration, and v3 to v4 migration. Applies to v3.4+ and v4 projects with 29 rules across 8 categories.
Share bugs, ideas, or general feedback.
Tailwind CSS is highly customizable through its configuration file, allowing you to define your design system, extend the default theme, and configure plugins.
The tailwind.config.js (or .ts, .cjs, .mjs) file is the heart of Tailwind customization:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./src/**/*.{html,js,jsx,ts,tsx}',
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {
// Custom theme extensions
},
},
plugins: [],
darkMode: 'class', // or 'media'
prefix: '',
important: false,
separator: ':',
}
The content array tells Tailwind where to look for class names:
module.exports = {
content: [
'./src/**/*.{html,js,jsx,ts,tsx}',
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
'./app/**/*.{js,ts,jsx,tsx}',
'./public/index.html',
],
// ...
}
For dynamic class names, use safelist or content transform:
module.exports = {
content: {
files: ['./src/**/*.{html,js}'],
transform: {
md: (content) => {
// Extract classes from markdown
return content
}
}
},
safelist: [
'bg-red-500',
'bg-green-500',
{
pattern: /bg-(red|green|blue)-(100|200|300)/,
},
],
}
Use theme.extend to add to existing values without replacing them:
module.exports = {
theme: {
extend: {
colors: {
brand: {
50: '#f0f9ff',
100: '#e0f2fe',
200: '#bae6fd',
300: '#7dd3fc',
400: '#38bdf8',
500: '#0ea5e9',
600: '#0284c7',
700: '#0369a1',
800: '#075985',
900: '#0c4a6e',
950: '#082f49',
},
primary: '#0ea5e9',
secondary: '#8b5cf6',
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
serif: ['Merriweather', 'serif'],
mono: ['Fira Code', 'monospace'],
},
spacing: {
'72': '18rem',
'84': '21rem',
'96': '24rem',
'128': '32rem',
},
borderRadius: {
'4xl': '2rem',
'5xl': '2.5rem',
},
fontSize: {
'xxs': '0.625rem',
},
boxShadow: {
'inner-lg': 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)',
},
animation: {
'spin-slow': 'spin 3s linear infinite',
'bounce-slow': 'bounce 2s infinite',
},
keyframes: {
wiggle: {
'0%, 100%': { transform: 'rotate(-3deg)' },
'50%': { transform: 'rotate(3deg)' },
}
},
},
},
}
Use theme (without extend) to replace default values:
module.exports = {
theme: {
// This replaces the default color palette entirely
colors: {
white: '#ffffff',
black: '#000000',
gray: {
100: '#f7fafc',
// ... custom gray scale
900: '#1a202c',
},
blue: {
500: '#0ea5e9',
},
},
},
}
Combine Tailwind with CSS variables for runtime theme switching:
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: 'rgb(var(--color-primary) / <alpha-value>)',
secondary: 'rgb(var(--color-secondary) / <alpha-value>)',
},
},
},
}
/* globals.css */
:root {
--color-primary: 14 165 233; /* RGB values */
--color-secondary: 139 92 246;
}
[data-theme='dark'] {
--color-primary: 56 189 248;
--color-secondary: 167 139 250;
}
Group related customizations for maintainability:
const colors = require('./theme/colors')
const typography = require('./theme/typography')
const spacing = require('./theme/spacing')
module.exports = {
theme: {
extend: {
...colors,
...typography,
...spacing,
},
},
}
Create custom utilities with plugins:
const plugin = require('tailwindcss/plugin')
module.exports = {
plugins: [
plugin(function({ addUtilities, addComponents, theme }) {
// Add custom utilities
addUtilities({
'.scrollbar-hide': {
'-ms-overflow-style': 'none',
'scrollbar-width': 'none',
'&::-webkit-scrollbar': {
display: 'none'
}
},
'.text-balance': {
'text-wrap': 'balance',
}
})
// Add custom components
addComponents({
'.btn': {
padding: theme('spacing.2') + ' ' + theme('spacing.4'),
borderRadius: theme('borderRadius.md'),
fontWeight: theme('fontWeight.semibold'),
'&:hover': {
opacity: 0.8,
}
}
})
})
],
}
Choose the appropriate dark mode strategy:
module.exports = {
// Class-based (manual control)
darkMode: 'class',
// Or media query-based (system preference)
// darkMode: 'media',
// Or custom selector
// darkMode: ['class', '[data-theme="dark"]'],
}
Configure for smaller bundle sizes:
module.exports = {
content: [
'./src/**/*.{html,js,jsx,ts,tsx}',
],
// Remove unused styles in production
purge: {
enabled: process.env.NODE_ENV === 'production',
},
}
import type { Config } from 'tailwindcss'
const config: Config = {
content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
colors: {
brand: {
DEFAULT: '#0ea5e9',
light: '#38bdf8',
dark: '#0284c7',
},
},
fontFamily: {
sans: ['var(--font-inter)', 'sans-serif'],
},
animation: {
'fade-in': 'fadeIn 0.5s ease-in-out',
'slide-up': 'slideUp 0.5s ease-out',
},
keyframes: {
fadeIn: {
'0%': { opacity: '0' },
'100%': { opacity: '1' },
},
slideUp: {
'0%': { transform: 'translateY(20px)', opacity: '0' },
'100%': { transform: 'translateY(0)', opacity: '1' },
},
},
},
},
plugins: [
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
require('@tailwindcss/aspect-ratio'),
],
darkMode: 'class',
}
export default config
const brandColors = {
brandA: {
primary: '#0ea5e9',
secondary: '#8b5cf6',
},
brandB: {
primary: '#10b981',
secondary: '#f59e0b',
},
}
const currentBrand = process.env.BRAND || 'brandA'
module.exports = {
theme: {
extend: {
colors: {
primary: brandColors[currentBrand].primary,
secondary: brandColors[currentBrand].secondary,
},
},
},
}
// tailwind.config.js
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
'./app/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {},
},
plugins: [],
}
// tailwind.config.js
module.exports = {
content: [
'./index.html',
'./src/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {},
},
plugins: [],
}
// tailwind.config.js
module.exports = {
content: [
'./index.html',
'./src/**/*.{vue,js,ts,jsx,tsx}',
],
theme: {
extend: {},
},
plugins: [],
}
const designTokens = {
colors: {
primary: {
50: '#eff6ff',
500: '#3b82f6',
900: '#1e3a8a',
},
},
spacing: {
xs: '0.25rem',
sm: '0.5rem',
md: '1rem',
lg: '1.5rem',
xl: '2rem',
},
}
module.exports = {
theme: {
extend: {
colors: designTokens.colors,
spacing: designTokens.spacing,
},
},
}
module.exports = {
theme: {
screens: {
'xs': '475px',
'sm': '640px',
'md': '768px',
'lg': '1024px',
'xl': '1280px',
'2xl': '1536px',
'3xl': '1920px',
},
},
}
module.exports = {
plugins: [
// Official plugins
require('@tailwindcss/forms')({
strategy: 'class', // or 'base'
}),
require('@tailwindcss/typography')({
className: 'prose',
}),
require('@tailwindcss/container-queries'),
// Custom plugin
require('./plugins/utilities'),
],
}
// Bad: Repeating values
module.exports = {
theme: {
extend: {
spacing: {
'custom': '17px',
},
width: {
'custom': '17px',
},
height: {
'custom': '17px',
},
},
},
}
// Good: Use spacing scale consistently
module.exports = {
theme: {
extend: {
spacing: {
'custom': '17px',
},
},
},
}
// Then use w-custom, h-custom, p-custom, etc.
// Bad: Accidentally keeping default colors
module.exports = {
theme: {
extend: {
colors: {
// This adds to the default palette, doesn't replace it
blue: { 500: '#custom-blue' }
},
},
},
}
// Good: Be explicit about replacing
module.exports = {
theme: {
colors: {
// This replaces the entire color palette
},
},
}
// Bad: Too specific, might miss files
module.exports = {
content: [
'./src/components/Button.tsx',
'./src/components/Card.tsx',
// ...hundreds of files
],
}
// Good: Use glob patterns
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
],
}
// Bad: Dynamic classes won't be included
<div className={`bg-${color}-500`}>
// Good: Add to safelist
module.exports = {
safelist: [
{
pattern: /bg-(red|green|blue|yellow)-(500|600|700)/,
},
],
}
// Better: Use complete class names
<div className={color === 'red' ? 'bg-red-500' : 'bg-blue-500'}>