Tailwind CSS Cheatsheet

Customization and Theme

Use this Tailwind CSS reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

v4 vs v3 Config Approach

Tailwind v4 moves configuration from tailwind.config.js into your CSS file using @theme. v3 uses a JavaScript config file.

Featurev3 (JS config)v4 (CSS @theme)
Colorstheme.extend.colors@theme { --color-* }
Fontstheme.extend.fontFamily@theme { --font-* }
Spacingtheme.extend.spacing@theme { --spacing-* }
Breakpointstheme.extend.screens@theme { --breakpoint-* }
Animationstheme.extend.keyframes@keyframes + @theme
Pluginsplugins: []CSS @plugin or JS

v4 Theme Configuration

Everything goes in your CSS entry file:

@import "tailwindcss";

@theme {
  /* Custom colors */
  --color-brand: #d4af37;
  --color-brand-light: #f8efb6;
  --color-surface: #ffffff;
  --color-on-surface: #0f172a;

  /* Custom fonts */
  --font-display: 'Cal Sans', sans-serif;
  --font-body: 'Inter', system-ui, sans-serif;

  /* Custom spacing */
  --spacing-18: 4.5rem;
  --spacing-88: 22rem;

  /* Custom breakpoints */
  --breakpoint-xs: 480px;
  --breakpoint-3xl: 1800px;

  /* Custom border radius */
  --radius-card: 0.875rem;

  /* Custom shadows */
  --shadow-card: 0 2px 8px 0 rgb(0 0 0 / 0.08);

  /* Custom animations */
  --animate-fade-in: fade-in 0.3s ease-out;
  --animate-slide-up: slide-up 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}

/* Custom keyframes */
@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes slide-up {
  from { transform: translateY(1rem); opacity: 0; }
  to { transform: translateY(0); opacity: 1; }
}

Usage of custom theme values:

<h1 class="font-display text-brand">Custom heading</h1>
<div class="bg-surface text-on-surface shadow-card rounded-card p-6">Card</div>
<div class="animate-fade-in">Fades in</div>
<div class="mt-18 max-w-[88rem]">Custom spacing</div>

No --z-* or --opacity-* theme namespaces exist — z-* and opacity-* accept bare values directly (z-1000, opacity-35) with no theme entry needed.

v4 CSS Variable Naming Convention

CategoryCSS variable prefixTailwind class prefix
Colors--color-*text-*, bg-*, border-* etc.
Font family--font-*font-*
Font size--text-*text-*
Font weight--font-weight-*font-*
Line height--leading-*leading-*
Letter spacing--tracking-*tracking-*
Spacing--spacing-*p-*, m-*, gap-*, w-*, h-* etc.
Border radius--radius-*rounded-*
Border width--border-*border-*
Shadows--shadow-*shadow-*
Blur--blur-*blur-*
Breakpoints--breakpoint-*sm:, md: etc.
Containers--container-*max-w-*, @sm: etc.
Duration--duration-*duration-*
Easing--ease-*ease-*
Animations--animate-*animate-*

v3 JavaScript Configuration

// tailwind.config.js
const defaultTheme = require('tailwindcss/defaultTheme')

module.exports = {
  content: ['./src/**/*.{html,js,jsx,ts,tsx,vue}'],
  theme: {
    // 'extend' merges with defaults; top-level REPLACES defaults
    extend: {
      colors: {
        brand: {
          DEFAULT: '#d4af37',
          light: '#f8efb6',
          dark: '#b8960e',
        },
        surface: 'var(--color-surface)',
      },
      fontFamily: {
        display: ['Cal Sans', ...defaultTheme.fontFamily.sans],
        sans: ['Inter', ...defaultTheme.fontFamily.sans],
      },
      spacing: {
        '18': '4.5rem',
        '88': '22rem',
      },
      screens: {
        'xs': '480px',
        '3xl': '1800px',
      },
      borderRadius: {
        'card': '0.875rem',
      },
      boxShadow: {
        'card': '0 2px 8px 0 rgb(0 0 0 / 0.08)',
      },
      keyframes: {
        'fade-in': {
          '0%': { opacity: '0' },
          '100%': { opacity: '1' },
        },
        'slide-up': {
          '0%': { transform: 'translateY(1rem)', opacity: '0' },
          '100%': { transform: 'translateY(0)', opacity: '1' },
        },
      },
      animation: {
        'fade-in': 'fade-in 0.3s ease-out',
        'slide-up': 'slide-up 0.4s cubic-bezier(0.16, 1, 0.3, 1)',
      },
    },
  },
  plugins: [
    require('@tailwindcss/typography'),
    require('@tailwindcss/forms'),
    require('@tailwindcss/aspect-ratio'),
    require('@tailwindcss/container-queries'),
  ],
}

Overriding Defaults (v3)

Remove the extend key to replace defaults entirely:

// tailwind.config.js
module.exports = {
  theme: {
    // REPLACES all default colors — only these exist
    colors: {
      transparent: 'transparent',
      black: '#000',
      white: '#fff',
      primary: '#3b82f6',
    },
    // REPLACES all default spacing
    spacing: {
      '0': '0',
      '1': '4px',
      '2': '8px',
      '4': '16px',
    }
  }
}

Custom Utilities (v4)

@import "tailwindcss";

/* Static custom utility */
@utility content-auto {
  content-visibility: auto;
}

/* Dynamic custom utility (matches theme keys) */
@theme {
  --tab-size-2: 2;
  --tab-size-4: 4;
  --tab-size-github: 8;
}

@utility tab-* {
  tab-size: --value(--tab-size-*);
}

/* Functional utility */
@utility scrollbar-hide {
  scrollbar-width: none;
  &::-webkit-scrollbar { display: none; }
}

Usage:

<div class="content-auto">...</div>
<div class="tab-4">...</div>
<div class="scrollbar-hide overflow-y-auto h-64">...</div>

Custom Utilities (v3)

// tailwind.config.js
const plugin = require('tailwindcss/plugin')

module.exports = {
  plugins: [
    plugin(function({ addUtilities, addComponents, theme, matchUtilities }) {
      // Static utilities
      addUtilities({
        '.scrollbar-hide': {
          'scrollbar-width': 'none',
          '&::-webkit-scrollbar': { display: 'none' },
        },
        '.content-auto': {
          'content-visibility': 'auto',
        },
      })

      // Dynamic utilities (tab-1, tab-2, tab-4, etc.)
      matchUtilities(
        { 'tab': (value) => ({ 'tab-size': value }) },
        { values: theme('spacing') }
      )
    })
  ]
}

Custom Variants (v4)

Define new variants in CSS with @custom-variant (@variant is the different directive for applying an existing variant inside your own CSS):

@import "tailwindcss";

/* Custom variant based on a data attribute */
@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));

/* Custom variant combining states */
@custom-variant hocus (&:hover, &:focus);

/* Custom variant for a specific parent */
@custom-variant sidebar-open (.sidebar-open &);

Usage:

<button class="hocus:bg-blue-700">Hover or focus</button>
<nav class="hidden sidebar-open:block">Visible when sidebar is open</nav>

Custom Variants (v3)

// tailwind.config.js
const plugin = require('tailwindcss/plugin')

module.exports = {
  plugins: [
    plugin(function({ addVariant }) {
      addVariant('hocus', ['&:hover', '&:focus'])
      addVariant('dark', '[data-theme="dark"] &')
      addVariant('sidebar-open', '.sidebar-open &')
    })
  ]
}

Plugins

Official Tailwind Plugins

PackageWhat it adds
@tailwindcss/typographyprose class for rich text
@tailwindcss/formsBetter form element defaults
@tailwindcss/container-queries@container support (v3)
@tailwindcss/aspect-ratioaspect-w-* / aspect-h-* (v3; built-in v3.2+)
/* v4 plugin registration */
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";

Third-party Plugin Examples

/* v4 */
@plugin "tailwindcss-animate";
@plugin "tailwind-scrollbar";

Safelist (Prevent Purging of Dynamic Classes)

v4.1+

@source inline(...) force-generates classes, with brace expansion for ranges. (v4.0 shipped without a safelist — upgrade to 4.1+ for this.)

@import "tailwindcss";

/* Individual classes */
@source inline("text-red-500 text-green-500 text-blue-500");

/* Brace expansion: bg-red-100 through bg-red-900 in steps of 100 */
@source inline("bg-red-{100..900..100}");

/* With variants */
@source inline("{hover:,}text-blue-{500,600}");

/* Exclude classes from ever being generated */
@source not inline("container");

v3

// tailwind.config.js
module.exports = {
  safelist: [
    'text-red-500',
    'bg-green-100',
    {
      pattern: /bg-(red|green|blue)-(100|500)/,
      variants: ['hover', 'focus'],
    },
  ],
}

Content Sources (Purging)

v4

v4 auto-detects content sources. Override or add:

@import "tailwindcss";
@source "../node_modules/my-ui-lib/**/*.js";
@source "./templates/**/*.html";

v3

// tailwind.config.js
module.exports = {
  content: [
    './pages/**/*.{html,js,jsx,ts,tsx}',
    './components/**/*.{js,jsx,ts,tsx}',
    './app/**/*.{js,jsx,ts,tsx}',
    // External library
    './node_modules/my-ui-lib/dist/**/*.js',
  ],
}

Using CSS Variables in Theme

v4 — automatic

Any @theme variable is usable in CSS and via Tailwind utilities:

@theme {
  --color-brand: #d4af37;
}

/* In CSS */
.my-element {
  color: var(--color-brand);
}
<!-- As Tailwind class -->
<p class="text-brand">Gold text</p>

v3 — with CSS variable colors

// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        brand: 'var(--color-brand)',
        // For opacity support, use hsl channel approach:
        primary: 'hsl(var(--primary-hsl) / <alpha-value>)',
      }
    }
  }
}
/* globals.css */
:root {
  --color-brand: #d4af37;
  --primary-hsl: 217 91% 60%;
}

Arbitrary Property (Any CSS)

For one-off CSS properties Tailwind doesn't cover:

<div class="[mask-type:luminance]">...</div>
<div class="[content-visibility:auto]">...</div>
<div class="[scroll-snap-align:start]">...</div>
<div class="[writing-mode:vertical-rl]">...</div>
<div class="[-webkit-text-stroke:1px_black]">...</div>

Responsive and state variants work:

<div class="hover:[transform:perspective(500px)_rotateY(6deg)]">3D hover</div>
<div class="lg:[column-count:3]">3 columns on large screens</div>

Theme Function (v3 in CSS)

Reference theme values in custom CSS using theme():

/* In CSS */
.custom-element {
  background-color: theme('colors.blue.500');
  padding: theme('spacing.4');
  border-radius: theme('borderRadius.lg');
  font-family: theme('fontFamily.sans');
  max-width: theme('screens.lg');
}

With opacity:

.custom {
  background-color: theme('colors.blue.500 / 50%');
}

Screen Function (v3 in CSS)

Target breakpoints in hand-written CSS:

@media screen(md) {
  .custom { display: flex; }
}

/* Equivalent to: */
@media (min-width: 768px) {
  .custom { display: flex; }
}