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.