Chapter 5: Configuration and Customization
Haiyue
18min
Chapter 5: Configuration and Customization
Learning Objectives
- Deep understanding of the tailwind.config.js configuration file
- Learn to extend the default theme and create design systems
- Master the use and development of the plugin system
- Understand production environment optimization and file size control
In-Depth Analysis of tailwind.config.js
Complete Configuration Structure
// tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme')
module.exports = {
// Content source configuration
content: [
'./src/**/*.{html,js,ts,jsx,tsx,vue,svelte}',
'./public/index.html',
// Include third-party libraries
'./node_modules/flowbite/**/*.js'
],
// Preset configuration
presets: [
// require('./my-preset.js')
],
// Dark mode
darkMode: 'class', // 'media' | 'class' | false
// Theme configuration
theme: {
// Completely replace default configuration
screens: {
'tablet': '640px',
'laptop': '1024px',
'desktop': '1280px',
},
// Extend default configuration
extend: {
// Add custom configurations here
}
},
// Variants configuration
variants: {
extend: {
// Extend variants
}
},
// Plugins
plugins: [
// Official plugins
require('@tailwindcss/forms'),
require('@tailwindcss/typography'),
require('@tailwindcss/aspect-ratio'),
// Custom plugins
require('./plugins/custom-plugin'),
],
// Core plugins configuration
corePlugins: {
// Disable specific core plugins
float: false,
objectFit: false,
},
// Prefix
prefix: 'tw-',
// Important
important: false, // true | '#app'
// Separator
separator: ':',
// CSS-in-JS configuration
corePlugins: {
preflight: false, // Disable base style reset
}
}
Content Configuration Best Practices
// Recommended content configuration
module.exports = {
content: {
files: [
'./src/**/*.{html,js,ts,jsx,tsx}',
'./components/**/*.{js,ts,jsx,tsx}',
'./pages/**/*.{js,ts,jsx,tsx}',
'./app/**/*.{js,ts,jsx,tsx}',
],
// Dynamic content extraction
extract: {
js: (content) => {
// Extract class names from JS files
return content.match(/[A-Za-z0-9_-]+/g) || []
}
},
// Transform content
transform: {
md: (content) => {
// Process Markdown files
return content.replace(/<!--.*?-->/gs, '')
}
}
},
// Safelist - ensure these classes are not purged
safelist: [
'bg-red-500',
'text-3xl',
'lg:text-4xl',
// Dynamically generated class names
/^bg-(red|green|blue)-(100|200|300|400|500)$/,
// Complex matching
{
pattern: /bg-(red|green|blue)-(100|200|300|400|500)/,
variants: ['lg', 'hover', 'focus', 'lg:hover'],
},
]
}
Theme Customization
Color System Customization
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
// Add brand colors
primary: {
50: '#eff6ff',
100: '#dbeafe',
200: '#bfdbfe',
300: '#93c5fd',
400: '#60a5fa',
500: '#3b82f6', // Main color
600: '#2563eb',
700: '#1d4ed8',
800: '#1e40af',
900: '#1e3a8a',
},
// Semantic colors
success: {
50: '#f0fdf4',
500: '#22c55e',
900: '#14532d',
},
danger: {
50: '#fef2f2',
500: '#ef4444',
900: '#7f1d1d',
},
warning: {
50: '#fefce8',
500: '#eab308',
900: '#713f12',
},
// Neutral colors
gray: {
50: '#fafafa',
100: '#f5f5f5',
200: '#e5e5e5',
300: '#d4d4d4',
400: '#a3a3a3',
500: '#737373',
600: '#525252',
700: '#404040',
800: '#262626',
900: '#171717',
},
// Single color values
'brand-blue': '#0066cc',
'accent': 'rgb(255, 107, 107)',
'custom-gray': 'hsl(210, 20%, 50%)',
}
}
}
}
Font System Customization
module.exports = {
theme: {
extend: {
fontFamily: {
// Add custom fonts
'sans': ['Inter', 'system-ui', ...defaultTheme.fontFamily.sans],
'serif': ['Merriweather', ...defaultTheme.fontFamily.serif],
'mono': ['JetBrains Mono', ...defaultTheme.fontFamily.mono],
'display': ['Oswald', 'Georgia', 'serif'],
'body': ['Open Sans', 'system-ui', 'sans-serif'],
'chinese': [
'PingFang SC',
'Hiragino Sans GB',
'Microsoft YaHei',
'WenQuanYi Micro Hei',
'sans-serif'
],
},
fontSize: {
// Custom font sizes
'xs': ['0.75rem', { lineHeight: '1rem' }],
'tiny': '0.625rem',
'7xl': '4.5rem',
'8xl': '6rem',
'9xl': '8rem',
},
fontWeight: {
'extra-light': 100,
'medium': 500,
'extra-bold': 800,
'black': 900,
},
letterSpacing: {
'tighter': '-0.05em',
'wider': '0.05em',
'widest': '0.25em',
},
lineHeight: {
'extra-tight': '1.1',
'extra-loose': '2.5',
}
}
}
}
Spacing and Sizing Customization
module.exports = {
theme: {
extend: {
spacing: {
// Add custom spacing
'0.5': '0.125rem', // 2px
'1.5': '0.375rem', // 6px
'2.5': '0.625rem', // 10px
'3.5': '0.875rem', // 14px
'15': '3.75rem', // 60px
'18': '4.5rem', // 72px
'72': '18rem', // 288px
'84': '21rem', // 336px
'96': '24rem', // 384px
'128': '32rem', // 512px
// Percentage spacing
'1/7': '14.2857143%',
'2/7': '28.5714286%',
'3/7': '42.8571429%',
'4/7': '57.1428571%',
'5/7': '71.4285714%',
'6/7': '85.7142857%',
// Viewport units
'screen-1/4': '25vh',
'screen-1/2': '50vh',
'screen-3/4': '75vh',
},
maxWidth: {
'8xl': '88rem',
'9xl': '96rem',
'1/4': '25%',
'1/2': '50%',
'3/4': '75%',
},
minHeight: {
'0': '0',
'1/4': '25%',
'1/2': '50%',
'3/4': '75%',
'full': '100%',
'screen': '100vh',
'screen-1/2': '50vh',
}
}
}
}
Breakpoint Customization
module.exports = {
theme: {
// Completely custom breakpoints
screens: {
'xs': '475px',
'sm': '640px',
'md': '768px',
'lg': '1024px',
'xl': '1280px',
'2xl': '1536px',
'3xl': '1920px',
// Named breakpoints
'mobile': '640px',
'tablet': '768px',
'laptop': '1024px',
'desktop': '1280px',
'wide': '1536px',
// Max width breakpoints
'max-sm': {'max': '639px'},
'max-md': {'max': '767px'},
'max-lg': {'max': '1023px'},
// Range breakpoints
'sm-md': {'min': '640px', 'max': '767px'},
'lg-xl': {'min': '1024px', 'max': '1279px'},
// Height breakpoints
'tall': {'raw': '(min-height: 800px)'},
'short': {'raw': '(max-height: 600px)'},
// Device-specific breakpoints
'print': {'raw': 'print'},
'landscape': {'raw': '(orientation: landscape)'},
'portrait': {'raw': '(orientation: portrait)'},
}
}
}
Plugin System
Official Plugins
# Install official plugins
npm install -D @tailwindcss/forms
npm install -D @tailwindcss/typography
npm install -D @tailwindcss/aspect-ratio
npm install -D @tailwindcss/line-clamp
npm install -D @tailwindcss/container-queries
// tailwind.config.js
module.exports = {
plugins: [
// Form style enhancement
require('@tailwindcss/forms')({
strategy: 'class', // 'base' | 'class'
}),
// Typography styles
require('@tailwindcss/typography')({
modifiers: ['sm', 'lg', 'xl', '2xl'],
}),
// Aspect ratio
require('@tailwindcss/aspect-ratio'),
// Text truncation
require('@tailwindcss/line-clamp'),
// Container queries
require('@tailwindcss/container-queries'),
],
}
Custom Utility Plugin
// plugins/utilities.js
const plugin = require('tailwindcss/plugin')
module.exports = plugin(function({ addUtilities, theme, variants }) {
const utilities = {
// Text shadow
'.text-shadow': {
textShadow: '2px 2px 4px rgba(0,0,0,0.1)',
},
'.text-shadow-md': {
textShadow: '4px 4px 6px rgba(0,0,0,0.1)',
},
'.text-shadow-lg': {
textShadow: '6px 6px 8px rgba(0,0,0,0.15)',
},
'.text-shadow-none': {
textShadow: 'none',
},
// 3D transforms
'.preserve-3d': {
transformStyle: 'preserve-3d',
},
'.perspective': {
perspective: '1000px',
},
'.backface-hidden': {
backfaceVisibility: 'hidden',
},
// Scroll behavior
'.scroll-smooth': {
scrollBehavior: 'smooth',
},
'.scroll-auto': {
scrollBehavior: 'auto',
},
// Custom cursors
'.cursor-grab': {
cursor: 'grab',
},
'.cursor-grabbing': {
cursor: 'grabbing',
},
}
addUtilities(utilities, ['responsive', 'hover', 'focus'])
})
Custom Component Plugin
// plugins/components.js
const plugin = require('tailwindcss/plugin')
module.exports = plugin(function({ addComponents, theme }) {
addComponents({
// Button component
'.btn': {
padding: `${theme('spacing.2')} ${theme('spacing.4')}`,
borderRadius: theme('borderRadius.md'),
fontWeight: theme('fontWeight.medium'),
fontSize: theme('fontSize.sm'),
lineHeight: theme('lineHeight.5'),
transition: 'all 0.15s ease-in-out',
cursor: 'pointer',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center',
border: '1px solid transparent',
textDecoration: 'none',
userSelect: 'none',
'&:focus': {
outline: '2px solid transparent',
boxShadow: `0 0 0 2px ${theme('colors.blue.500')}`,
},
'&:disabled': {
opacity: '0.5',
cursor: 'not-allowed',
},
},
'.btn-primary': {
backgroundColor: theme('colors.blue.500'),
color: theme('colors.white'),
'&:hover:not(:disabled)': {
backgroundColor: theme('colors.blue.600'),
},
},
'.btn-secondary': {
backgroundColor: theme('colors.gray.200'),
color: theme('colors.gray.900'),
'&:hover:not(:disabled)': {
backgroundColor: theme('colors.gray.300'),
},
},
'.btn-outline': {
backgroundColor: 'transparent',
borderColor: theme('colors.gray.300'),
color: theme('colors.gray.700'),
'&:hover:not(:disabled)': {
backgroundColor: theme('colors.gray.50'),
borderColor: theme('colors.gray.400'),
},
},
// Form component
'.form-input': {
width: '100%',
padding: `${theme('spacing.2')} ${theme('spacing.3')}`,
backgroundColor: theme('colors.white'),
border: `1px solid ${theme('colors.gray.300')}`,
borderRadius: theme('borderRadius.md'),
fontSize: theme('fontSize.sm'),
lineHeight: theme('lineHeight.5'),
transition: 'border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out',
'&:focus': {
outline: 'none',
borderColor: theme('colors.blue.500'),
boxShadow: `0 0 0 1px ${theme('colors.blue.500')}`,
},
'&::placeholder': {
color: theme('colors.gray.400'),
},
},
// Card component
'.card': {
backgroundColor: theme('colors.white'),
borderRadius: theme('borderRadius.lg'),
boxShadow: theme('boxShadow.md'),
border: `1px solid ${theme('colors.gray.200')}`,
overflow: 'hidden',
},
'.card-header': {
padding: theme('spacing.4'),
borderBottom: `1px solid ${theme('colors.gray.200')}`,
backgroundColor: theme('colors.gray.50'),
},
'.card-body': {
padding: theme('spacing.4'),
},
'.card-footer': {
padding: theme('spacing.4'),
backgroundColor: theme('colors.gray.50'),
borderTop: `1px solid ${theme('colors.gray.200')}`,
},
})
})
Dynamic Utility Plugin
// plugins/dynamic-utilities.js
const plugin = require('tailwindcss/plugin')
module.exports = plugin(function({ matchUtilities, theme }) {
// Dynamic spacing utilities
matchUtilities(
{
'auto-fit': (value) => ({
gridTemplateColumns: `repeat(auto-fit, minmax(${value}, 1fr))`,
}),
'auto-fill': (value) => ({
gridTemplateColumns: `repeat(auto-fill, minmax(${value}, 1fr))`,
}),
},
{
values: theme('width'),
respectPrefix: false,
respectImportant: false,
}
)
// Dynamic shadow utilities
matchUtilities(
{
'text-shadow': (value) => ({
textShadow: value,
}),
},
{
values: {
sm: '1px 1px 2px rgba(0, 0, 0, 0.1)',
default: '2px 2px 4px rgba(0, 0, 0, 0.1)',
md: '4px 4px 8px rgba(0, 0, 0, 0.12)',
lg: '8px 8px 16px rgba(0, 0, 0, 0.15)',
xl: '12px 12px 24px rgba(0, 0, 0, 0.2)',
},
}
)
})
Dark Mode Support
Configure Dark Mode
// tailwind.config.js
module.exports = {
darkMode: 'class', // 'media' | 'class' | ['class', '[data-mode="dark"]']
theme: {
extend: {
colors: {
// Dark mode specific colors
dark: {
50: '#f9fafb',
100: '#f3f4f6',
200: '#e5e7eb',
300: '#d1d5db',
400: '#9ca3af',
500: '#6b7280',
600: '#4b5563',
700: '#374151',
800: '#1f2937',
900: '#111827',
}
}
}
}
}
Using Dark Mode
<!-- HTML structure -->
<html class="dark">
<body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
<div class="bg-white dark:bg-gray-800 shadow-lg">
<h1 class="text-gray-900 dark:text-white">Title</h1>
<p class="text-gray-600 dark:text-gray-300">Content</p>
<button class="bg-blue-500 dark:bg-blue-600 text-white hover:bg-blue-600 dark:hover:bg-blue-700">
Button
</button>
</div>
</body>
</html>
/* CSS custom properties for dark mode support */
@layer base {
:root {
--color-primary: 59 130 246; /* blue-500 */
--color-background: 255 255 255; /* white */
--color-text: 17 24 39; /* gray-900 */
}
.dark {
--color-primary: 37 99 235; /* blue-600 */
--color-background: 17 24 39; /* gray-900 */
--color-text: 249 250 251; /* gray-50 */
}
}
.custom-bg {
background-color: rgb(var(--color-background));
}
.custom-text {
color: rgb(var(--color-text));
}
Production Environment Optimization
PurgeCSS Configuration
// tailwind.config.js
module.exports = {
content: {
files: [
'./src/**/*.{html,js,ts,jsx,tsx}',
],
options: {
// Safelist - classes that should never be purged
safelist: [
'bg-red-500',
'text-center',
/^bg-(red|green|blue)-(100|200|300|400|500|600|700|800|900)$/,
{
pattern: /^(bg|text|border)-(red|green|blue)-(100|500|900)$/,
variants: ['hover', 'focus', 'lg:hover'],
},
],
// Blocklist - prevent deletion
blocklist: [
'container',
'collapsible',
],
// Default extractor
defaultExtractor: content => content.match(/[\w-/:]+/g) || [],
// Custom extractors
extractors: [
{
extractor: content => {
// Extract class names from Vue components
return content.match(/[A-Za-z0-9_-]+/g) || []
},
extensions: ['vue']
}
]
}
}
}
File Size Optimization
// postcss.config.js - Production configuration
module.exports = {
plugins: [
require('tailwindcss'),
require('autoprefixer'),
...(process.env.NODE_ENV === 'production'
? [
require('cssnano')({
preset: ['default', {
discardComments: { removeAll: true },
normalizeWhitespace: false,
}]
})
]
: []
),
],
}
Build Script Optimization
{
"scripts": {
"build:css": "tailwindcss -i ./src/input.css -o ./dist/output.css",
"build:css:watch": "tailwindcss -i ./src/input.css -o ./dist/output.css --watch",
"build:css:prod": "NODE_ENV=production tailwindcss -i ./src/input.css -o ./dist/output.css --minify",
"analyze:css": "tailwindcss -i ./src/input.css -o ./dist/output.css --content './src/**/*.{html,js}' --verbose"
}
}
Summary
Through this chapter, you should have mastered:
- Configuration System: Comprehensive understanding of all tailwind.config.js configurations
- Theme Customization: Creating color, font, and spacing systems that match your brand
- Plugin Development: Writing custom utility and component plugins
- Dark Mode: Implementing complete dark theme support
- Performance Optimization: File size control strategies for production environments
These configuration and customization skills enable you to transform Tailwind CSS into a CSS framework that fully meets your project requirements.