Tailwind CSS Cheatsheet
Dark Mode
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.
How Dark Mode Works
Tailwind's dark: variant activates dark-mode styles. The trigger strategy determines when it activates.
Strategy: Media Query (default)
Activates when the OS/browser is set to dark mode. No configuration needed in v4; in v3 this is the default.
<div class="bg-white text-slate-900 dark:bg-slate-900 dark:text-white"> Adapts to OS preference </div>
Strategy: Class Toggle (v3)
Activate dark mode by adding a class to <html> — gives you manual control.
// tailwind.config.js (v3) module.exports = { darkMode: 'class', // ... }
<!-- Add 'dark' class to html element to activate --> <html class="dark"> <body> <div class="dark:bg-slate-900">Dark background</div> </body> </html>
Toggle via JavaScript:
<script> // Toggle dark mode document.documentElement.classList.toggle('dark') // Set from localStorage if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) { document.documentElement.classList.add('dark') } else { document.documentElement.classList.remove('dark') } </script>
Strategy: Data Attribute (v3.4+ / v4)
Use a data-* attribute on the root element instead of a class — avoids class conflicts.
// tailwind.config.js (v3.4+) module.exports = { darkMode: ['selector', '[data-theme="dark"]'], }
/* v4 — in your CSS */ @import "tailwindcss"; @custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));
<html data-theme="dark"> <div class="dark:bg-slate-900">Activated by data attribute</div> </html>
Strategy: Class Toggle (v4)
Redefine the dark variant to key off a class instead of the media query:
@import "tailwindcss"; @custom-variant dark (&:where(.dark, .dark *));
<div class="dark"> <p class="text-slate-900 dark:text-white">Only dark inside .dark container</p> </div>
Using the dark: Variant
Any utility can be prefixed with dark::
<!-- Colors --> <body class="bg-white text-slate-900 dark:bg-slate-950 dark:text-slate-50"> <!-- Borders --> <div class="border border-slate-200 dark:border-slate-700"> <!-- Shadows --> <div class="shadow-md dark:shadow-slate-900/50"> <!-- Typography --> <p class="text-slate-600 dark:text-slate-400">Muted text</p> <h2 class="text-slate-900 dark:text-white">Heading</h2> <!-- Backgrounds with opacity --> <div class="bg-slate-100 dark:bg-slate-800">Surface</div> <div class="bg-white/80 dark:bg-slate-900/80">Translucent</div> <!-- Interactive states in dark mode --> <button class="bg-blue-600 hover:bg-blue-700 dark:bg-blue-500 dark:hover:bg-blue-400 text-white"> Button </button>
Common Dark Mode Patterns
Page background and text
<html class="bg-white text-slate-900 dark:bg-slate-950 dark:text-slate-50">
Card component
<div class="bg-white border border-slate-200 rounded-xl shadow-sm p-6 dark:bg-slate-800 dark:border-slate-700 dark:shadow-slate-900/50"> <h3 class="font-semibold text-slate-900 dark:text-white">Card Title</h3> <p class="text-slate-600 dark:text-slate-400 mt-1">Card description</p> </div>
Input field
<input class="w-full border border-slate-300 rounded-lg px-3 py-2 bg-white text-slate-900 placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent dark:bg-slate-800 dark:border-slate-600 dark:text-white dark:placeholder:text-slate-500" type="text" placeholder="Search..." >
Navigation
<nav class="bg-white border-b border-slate-200 dark:bg-slate-900 dark:border-slate-700"> <a href="/" class="text-slate-700 hover:text-slate-900 dark:text-slate-300 dark:hover:text-white"> Home </a> </nav>
Code block
<pre class="bg-slate-100 dark:bg-slate-900 rounded-lg p-4 text-sm overflow-x-auto"> <code class="text-slate-800 dark:text-slate-200">code here</code> </pre>
Badge / pill
<span class="bg-blue-100 text-blue-700 dark:bg-blue-900/30 dark:text-blue-400 text-xs font-medium px-2.5 py-0.5 rounded-full"> Badge </span>
Frosted glass in dark mode
<div class="bg-white/80 backdrop-blur-md border border-slate-200/60 rounded-2xl dark:bg-slate-900/80 dark:border-slate-700/60"> Frosted glass </div>
Prevent Flash of Wrong Theme
Add an inline script before any CSS loads to read the stored preference:
<head> <script> // Prevent FOUC const theme = localStorage.getItem('theme') if (theme === 'dark' || (!theme && window.matchMedia('(prefers-color-scheme: dark)').matches)) { document.documentElement.classList.add('dark') } </script> <!-- CSS loads after — no flash --> </head>
Combining dark: with Other Variants
Dark mode stacks with any other variant:
<!-- dark + hover --> <button class="dark:hover:bg-slate-700">...</button> <!-- dark + responsive --> <div class="dark:md:text-lg">...</div> <!-- dark + focus --> <input class="dark:focus:ring-blue-400"> <!-- dark + group-hover --> <div class="group"> <p class="group-hover:text-blue-600 dark:group-hover:text-blue-400">...</p> </div> <!-- dark + disabled --> <button class="dark:disabled:opacity-40" disabled>...</button> <!-- dark + first-child --> <li class="dark:first:border-t-0">...</li>
System-Level vs. Manual Toggle
Using both (respect system unless user has picked)
<script> // On page load function applyTheme(theme) { if (theme === 'dark') { document.documentElement.classList.add('dark') } else { document.documentElement.classList.remove('dark') } } const stored = localStorage.getItem('theme') if (stored) { applyTheme(stored) } else { // System preference applyTheme(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light') } </script>
Theme toggle button
<button onclick=" const isDark = document.documentElement.classList.toggle('dark'); localStorage.setItem('theme', isDark ? 'dark' : 'light'); " class="p-2 rounded-lg text-slate-500 hover:text-slate-900 dark:text-slate-400 dark:hover:text-white transition-colors" aria-label="Toggle dark mode" > <!-- Sun icon (shown in dark mode) --> <svg class="hidden dark:block size-5" ...></svg> <!-- Moon icon (shown in light mode) --> <svg class="block dark:hidden size-5" ...></svg> </button>
Swapping Images for Dark Mode
<!-- CSS display swap approach --> <img class="block dark:hidden" src="logo-light.png" alt="Logo"> <img class="hidden dark:block" src="logo-dark.png" alt="Logo"> <!-- CSS filter approach (quick invert) --> <img class="dark:invert" src="logo-black.svg" alt="Logo"> <!-- picture element (no JS, respects media query) --> <picture> <source srcset="logo-dark.png" media="(prefers-color-scheme: dark)"> <img src="logo-light.png" alt="Logo"> </picture>
Dark Mode Color Palette Tips
| Light | Dark equivalent |
|---|---|
bg-white | dark:bg-slate-950 |
bg-slate-50 (surface) | dark:bg-slate-900 |
bg-slate-100 (raised) | dark:bg-slate-800 |
text-slate-900 (primary) | dark:text-white |
text-slate-700 (body) | dark:text-slate-300 |
text-slate-500 (muted) | dark:text-slate-400 |
border-slate-200 | dark:border-slate-700 |
border-slate-100 | dark:border-slate-800 |
Using CSS variables for dark mode tokens (v4 recommended approach) — register the tokens once in @theme, then override the plain CSS variables under your dark selector:
@theme {
--color-surface: #ffffff;
--color-on-surface: #0f172a;
}
@layer base {
.dark {
--color-surface: #0f172a;
--color-on-surface: #f8fafc;
}
}<div class="bg-surface text-on-surface">Themed automatically</div>