Tailwind CSS Dark Mode & Theme Configuration: dark Prefix and @theme Directive

Dark Mode (dark:)

Tailwind uses the dark: prefix to define styles for dark mode, supporting both media and class strategies.

Example

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Dark Mode Demo</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script>
    tailwind.config = {
      darkMode: 'class'
    }
  </script>
</head>
<body class="min-h-screen bg-white dark:bg-gray-900 transition-colors">
  <div class="max-w-4xl mx-auto p-8 space-y-8">
    <!-- Dark mode toggle button -->
    <div class="flex justify-end">
      <button onclick="document.documentElement.classList.toggle('dark')"
              class="p-2 rounded-lg bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200">
        Toggle Dark Mode
      </button>
    </div>

    <!-- Text colors -->
    <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
      <h3 class="text-gray-900 dark:text-white font-semibold text-lg mb-4">Text Colors</h3>
      <p class="text-gray-600 dark:text-gray-300">
        This text appears dark gray in light mode and light gray in dark mode.
      </p>
      <p class="text-blue-600 dark:text-blue-400 mt-2">
        Link colors also adapt based on the mode.
      </p>
    </div>

    <!-- Card components -->
    <div class="grid grid-cols-1 md:grid-cols-2 gap-6">
      <div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg dark:shadow-gray-700/50 p-6">
        <div class="w-12 h-12 bg-blue-100 dark:bg-blue-900 rounded-lg flex items-center justify-center mb-4">
          <span class="text-blue-600 dark:text-blue-400 text-xl">🎨</span>
        </div>
        <h4 class="text-gray-900 dark:text-white font-semibold mb-2">Theme Adaptation</h4>
        <p class="text-gray-600 dark:text-gray-400">Card backgrounds, shadows, and text colors all adapt to dark mode.</p>
      </div>
      <div class="bg-white dark:bg-gray-800 rounded-lg shadow-lg dark:shadow-gray-700/50 p-6">
        <div class="w-12 h-12 bg-green-100 dark:bg-green-900 rounded-lg flex items-center justify-center mb-4">
          <span class="text-green-600 dark:text-green-400 text-xl">✨</span>
        </div>
        <h4 class="text-gray-900 dark:text-white font-semibold mb-2">Smooth Transitions</h4>
        <p class="text-gray-600 dark:text-gray-400">Combined with transition-colors for smooth color switching.</p>
      </div>
    </div>

    <!-- Form elements -->
    <div class="bg-white dark:bg-gray-800 rounded-lg shadow p-6">
      <h3 class="text-gray-900 dark:text-white font-semibold mb-4">Form Elements</h3>
      <div class="space-y-4">
        <input type="text" placeholder="Input field"
               class="w-full p-3 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-400 dark:placeholder-gray-500 focus:ring-2 focus:ring-blue-500 dark:focus:ring-blue-400">
        <button class="w-full p-3 bg-blue-600 dark:bg-blue-500 text-white rounded-lg hover:bg-blue-700 dark:hover:bg-blue-600 transition-colors">
          Submit Button
        </button>
      </div>
    </div>
  </div>
</body>
</html>
▶ Try it Yourself

Traditional CSS vs Tailwind The traditional approach requires writing @media (prefers-color-scheme: dark) or manually adding .dark classes with numerous CSS rules, whereas Tailwind uses prefixes like dark:bg-gray-900 dark:text-white for inline declarations.

💡 Tip: The darkMode: 'class' strategy requires toggling the dark class on the <html> element. The darkMode: 'media' strategy automatically follows the system preference.

Custom Theme (tailwind.config)

You can extend or override the default theme through the tailwind.config file, adding custom colors, fonts, spacing, and more.

Example

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Custom Theme Demo</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: {
              50: '#eff6ff',
              100: '#dbeafe',
              200: '#bfdbfe',
              300: '#93c5fd',
              400: '#60a5fa',
              500: '#3b82f6',
              600: '#2563eb',
              700: '#1d4ed8',
              800: '#1e40af',
              900: '#1e3a8a',
            },
            accent: '#f59e0b',
            brand: '#8b5cf6',
          },
          fontFamily: {
            sans: ['Inter', 'system-ui', 'sans-serif'],
            display: ['Poppins', 'sans-serif'],
          },
          spacing: {
            '128': '32rem',
            '144': '36rem',
          },
          borderRadius: {
            '4xl': '2rem',
          },
        },
      },
    }
  </script>
</head>
<body class="min-h-screen bg-gray-100 p-8">
  <div class="max-w-4xl mx-auto space-y-8">
    <!-- Custom colors -->
    <div class="bg-white rounded-lg shadow p-6">
      <h3 class="font-semibold mb-4">Custom Colors</h3>
      <div class="flex flex-wrap gap-4">
        <div class="w-20 h-20 bg-primary-500 rounded-lg flex items-center justify-center text-white text-xs">primary-500</div>
        <div class="w-20 h-20 bg-primary-600 rounded-lg flex items-center justify-center text-white text-xs">primary-600</div>
        <div class="w-20 h-20 bg-primary-700 rounded-lg flex items-center justify-center text-white text-xs">primary-700</div>
        <div class="w-20 h-20 bg-accent rounded-lg flex items-center justify-center text-white text-xs">accent</div>
        <div class="w-20 h-20 bg-brand rounded-lg flex items-center justify-center text-white text-xs">brand</div>
      </div>
    </div>

    <!-- Custom fonts -->
    <div class="bg-white rounded-lg shadow p-6">
      <h3 class="font-semibold mb-4">Custom Fonts</h3>
      <p class="font-sans text-lg mb-2">font-sans: Using Inter font</p>
      <p class="font-display text-lg">font-display: Using Poppins font</p>
    </div>

    <!-- Custom spacing -->
    <div class="bg-white rounded-lg shadow p-6">
      <h3 class="font-semibold mb-4">Custom Spacing</h3>
      <div class="space-y-2">
        <div class="h-4 bg-primary-200 rounded" style="width: 32rem;">
          <span class="text-xs">w-128 (32rem)</span>
        </div>
        <div class="h-4 bg-primary-300 rounded" style="width: 36rem;">
          <span class="text-xs">w-144 (36rem)</span>
        </div>
      </div>
    </div>

    <!-- Custom border radius -->
    <div class="bg-white rounded-lg shadow p-6">
      <h3 class="font-semibold mb-4">Custom Border Radius</h3>
      <div class="flex gap-4">
        <div class="w-24 h-24 bg-brand rounded-4xl flex items-center justify-center text-white text-xs">rounded-4xl</div>
        <div class="w-24 h-24 bg-accent rounded-full flex items-center justify-center text-white text-xs">rounded-full</div>
      </div>
    </div>
  </div>
</body>
</html>
▶ Try it Yourself

Traditional CSS vs Tailwind The traditional approach requires defining numerous variables and classes in CSS, whereas Tailwind extends the theme through the extend option in tailwind.config, automatically generating corresponding utility classes.

@theme Directive (v4 New Feature)

Tailwind v4 introduces the @theme directive, using CSS-native syntax to define theme variables without needing a JavaScript configuration file.

Example

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>@theme Directive Demo</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <style type="text/tailwindcss">
    @theme {
      --color-primary-50: #eff6ff;
      --color-primary-100: #dbeafe;
      --color-primary-200: #bfdbfe;
      --color-primary-300: #93c5fd;
      --color-primary-400: #60a5fa;
      --color-primary-500: #3b82f6;
      --color-primary-600: #2563eb;
      --color-primary-700: #1d4ed8;
      --color-primary-800: #1e40af;
      --color-primary-900: #1e3a8a;

      --color-accent: #f59e0b;
      --color-brand: #8b5cf6;

      --font-sans: 'Inter', system-ui, sans-serif;
      --font-display: 'Poppins', sans-serif;

      --spacing-128: 32rem;
      --spacing-144: 36rem;

      --radius-4xl: 2rem;
    }
  </style>
</head>
<body class="min-h-screen bg-gray-100 p-8">
  <div class="max-w-4xl mx-auto space-y-8">
    <!-- Colors defined with @theme -->
    <div class="bg-white rounded-lg shadow p-6">
      <h3 class="font-semibold mb-4">Colors Defined with @theme</h3>
      <div class="flex flex-wrap gap-4">
        <div class="w-20 h-20 bg-primary-500 rounded-lg flex items-center justify-center text-white text-xs">primary-500</div>
        <div class="w-20 h-20 bg-primary-600 rounded-lg flex items-center justify-center text-white text-xs">primary-600</div>
        <div class="w-20 h-20 bg-accent rounded-lg flex items-center justify-center text-white text-xs">accent</div>
        <div class="w-20 h-20 bg-brand rounded-lg flex items-center justify-center text-white text-xs">brand</div>
      </div>
    </div>

    <!-- Fonts defined with @theme -->
    <div class="bg-white rounded-lg shadow p-6">
      <h3 class="font-semibold mb-4">Fonts Defined with @theme</h3>
      <p class="font-sans text-lg mb-2">font-sans: Using Inter font</p>
      <p class="font-display text-lg">font-display: Using Poppins font</p>
    </div>

    <!-- Spacing defined with @theme -->
    <div class="bg-white rounded-lg shadow p-6">
      <h3 class="font-semibold mb-4">Spacing Defined with @theme</h3>
      <div class="space-y-2">
        <div class="h-4 bg-primary-200 rounded w-128">
          <span class="text-xs">w-128 (32rem)</span>
        </div>
        <div class="h-4 bg-primary-300 rounded w-144">
          <span class="text-xs">w-144 (36rem)</span>
        </div>
      </div>
    </div>

    <!-- Border radius defined with @theme -->
    <div class="bg-white rounded-lg shadow p-6">
      <h3 class="font-semibold mb-4">Border Radius Defined with @theme</h3>
      <div class="flex gap-4">
        <div class="w-24 h-24 bg-brand rounded-4xl flex items-center justify-center text-white text-xs">rounded-4xl</div>
      </div>
    </div>
  </div>
</body>
</html>
▶ Try it Yourself

Traditional CSS vs Tailwind The traditional approach requires defining themes using JavaScript objects in tailwind.config.js, whereas Tailwind v4's @theme directive uses CSS-native variable syntax, which is more intuitive and compatible with native CSS variables.

💡 Tip: Variable names in the @theme directive follow naming conventions like --color-*, --font-*, --spacing-*, --radius-*, etc. Tailwind automatically generates corresponding utility classes.

CSS Native Variables and Tailwind Integration

Tailwind v4 supports using CSS native variables directly, without needing to go through a configuration file.

Example

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>CSS Native Variable Integration</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <style>
    :root {
      --main-bg: #f8fafc;
      --card-bg: #ffffff;
      --text-primary: #1e293b;
      --text-secondary: #64748b;
      --border-color: #e2e8f0;
      --spacing-section: 2rem;
    }

    .dark {
      --main-bg: #0f172a;
      --card-bg: #1e293b;
      --text-primary: #f1f5f9;
      --text-secondary: #94a3b8;
      --border-color: #334155;
    }
  </style>
</head>
<body class="min-h-screen p-8" style="background-color: var(--main-bg);">
  <div class="max-w-4xl mx-auto space-y-8" style="gap: var(--spacing-section);">
    <!-- Dark mode toggle -->
    <div class="flex justify-end">
      <button onclick="document.documentElement.classList.toggle('dark')"
              class="p-2 rounded-lg" style="background-color: var(--card-bg); color: var(--text-primary);">
        Toggle Dark Mode
      </button>
    </div>

    <!-- Card using CSS variables -->
    <div class="rounded-lg shadow p-6" style="background-color: var(--card-bg); border: 1px solid var(--border-color);">
      <h3 class="font-semibold text-lg mb-4" style="color: var(--text-primary);">CSS Native Variables</h3>
      <p style="color: var(--text-secondary);">
        This card uses CSS native variables to define colors, applied via the style attribute.
      </p>
    </div>

    <!-- Mixed usage -->
    <div class="rounded-lg shadow p-6 bg-white dark:bg-gray-800">
      <h3 class="font-semibold text-lg mb-4 text-gray-900 dark:text-white">Mixed Usage</h3>
      <p class="text-gray-600 dark:text-gray-300 mb-4">
        You can use both Tailwind classes and CSS variables together.
      </p>
      <div class="flex gap-4">
        <div class="w-16 h-16 rounded-lg" style="background-color: var(--text-primary);"></div>
        <div class="w-16 h-16 rounded-lg bg-blue-500"></div>
        <div class="w-16 h-16 rounded-lg" style="background-color: var(--border-color);"></div>
      </div>
    </div>
  </div>
</body>
</html>
▶ Try it Yourself
💡 Tip: CSS native variables are best suited for values that need to be dynamically modified at runtime (such as theme switching), while Tailwind classes are ideal for static styles.

Plugin System Introduction

Tailwind plugins can extend the framework's functionality by adding custom utility classes, variants, or base styles.

Example

HTML
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Plugin System Demo</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <script>
    const plugin = tailwind.plugin;

    // Custom plugin: add text gradient utility classes
    const textGradientPlugin = plugin(function({ addUtilities }) {
      addUtilities({
        '.text-gradient-blue': {
          'background': 'linear-gradient(to right, #3b82f6, #8b5cf6)',
          '-webkit-background-clip': 'text',
          '-webkit-text-fill-color': 'transparent',
          'background-clip': 'text',
        },
        '.text-gradient-red': {
          'background': 'linear-gradient(to right, #ef4444, #f97316)',
          '-webkit-background-clip': 'text',
          '-webkit-text-fill-color': 'transparent',
          'background-clip': 'text',
        },
      });
    });

    tailwind.config = {
      plugins: [textGradientPlugin],
    }
  </script>
</head>
<body class="min-h-screen bg-gray-100 p-8">
  <div class="max-w-4xl mx-auto space-y-8">
    <!-- Utility classes added by the plugin -->
    <div class="bg-white rounded-lg shadow p-6">
      <h3 class="font-semibold mb-4">Custom Plugin: Text Gradient</h3>
      <p class="text-4xl font-bold text-gradient-blue mb-4">Blue gradient text</p>
      <p class="text-4xl font-bold text-gradient-red">Red gradient text</p>
    </div>

    <!-- Common third-party plugin examples -->
    <div class="bg-white rounded-lg shadow p-6">
      <h3 class="font-semibold mb-4">Common Plugins</h3>
      <div class="space-y-4">
        <div class="p-4 bg-gray-50 rounded-lg">
          <h4 class="font-medium text-gray-900">@tailwindcss/typography</h4>
          <p class="text-gray-600 text-sm">Provides beautiful typographic styles for long-form content using the prose class.</p>
        </div>
        <div class="p-4 bg-gray-50 rounded-lg">
          <h4 class="font-medium text-gray-900">@tailwindcss/forms</h4>
          <p class="text-gray-600 text-sm">Provides base style resets for form elements, ensuring consistent behavior across browsers.</p>
        </div>
        <div class="p-4 bg-gray-50 rounded-lg">
          <h4 class="font-medium text-gray-900">@tailwindcss/aspect-ratio</h4>
          <p class="text-gray-600 text-sm">Provides aspect-ratio utility classes for controlling element width-to-height ratios.</p>
        </div>
      </div>
    </div>
  </div>
</body>
</html>
▶ Try it Yourself

Traditional CSS vs Tailwind The traditional approach requires manually writing CSS classes and importing them, whereas Tailwind plugins automatically integrate into the build process through APIs like addUtilities, addComponents, and addBase.

⚠️ Note: The plugin API has changed in Tailwind v4. It is recommended to use CSS-native approaches to extend functionality. The @theme directive and @layer can replace most plugin use cases.

❓ FAQ

Q What is the difference between darkMode: 'class' and darkMode: 'media'?
A The 'media' strategy automatically follows the system's prefers-color-scheme media query, and users cannot manually toggle it. The 'class' strategy requires manually toggling the dark class on the <html> element, which is suitable for scenarios where a toggle button is provided.
Q What is the difference between the @theme directive and tailwind.config?
A tailwind.config defines themes using JavaScript objects and requires a configuration file. The @theme directive uses CSS-native variable syntax, defined directly in CSS. It is a new feature in Tailwind v4 and is the recommended approach.
Q How do I use different images in dark mode?
A Use the dark: prefix with hidden and block. For example, <img class="block dark:hidden" src="light.png"> and <img class="hidden dark:block" src="dark.png">.
Q How should I choose between CSS variables and Tailwind classes?
A Prefer Tailwind classes for static styles, and use CSS variables for values that need to be dynamically modified at runtime. Both can be mixed, such as style="color: var(--text-primary)".

📖 Summary

📝 Exercises

  1. ⭐ Create a login page that supports dark mode, including input fields, buttons, and cards, using the dark: prefix to adapt all elements

  2. ⭐⭐ Use the @theme directive to customize a brand theme (including primary color, secondary color, and fonts), and create a showcase page

  3. ⭐⭐⭐ Create a theme switcher that supports light/dark/system modes, using CSS variables for dynamic theme color switching

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏