
Master Dark Mode in Tailwind CSS 4.0: Seamless Toggle Setup with npm
Introduction: Briefly explain the popularity of dark mode and Tailwind CSS 4.0’s role.
Setting Up Dark Mode: Detail the HTML, CSS, and JavaScript for the toggle (based on the CDN example).
Why npm Fails: Explain common npm installation issues (e.g., misconfigured tailwind.config.js, PostCSS, or content paths).
Step-by-Step Fix: Provide the npm setup and troubleshooting steps.
Bonus Tips: Add localStorage for theme persistence or framework-specific notes.
Conclusion: Recap the benefits of a working dark mode toggle.

- Verify Tailwind CSS Installation
Ensure Tailwind CSS 4.0 is correctly installed. Run:
npm install tailwindcss@latest @tailwindcss/postcss@latest
This installs the latest Tailwind CSS 4.0 and its PostCSS plugin. Check your package.json
to confirm the version:
"dependencies": {
"tailwindcss": "^4.0.0",
"@tailwindcss/postcss": "^4.0.0"
}
- Check
tailwind.config.js
Tailwind CSS 4.0 uses theclass
strategy for dark mode by default, but it’s good to ensure it’s explicitly set. Create or update yourtailwind.config.js
:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{html,js,ts,jsx,tsx}"],
darkMode: 'class', // Explicitly set to 'class'
theme: {
extend: {},
},
plugins: [],
};
- Content Paths: Ensure the
content
array includes all files where Tailwind classes are used (e.g., HTML, JS, TS, JSX, TSX). Incorrect paths can prevent Tailwind from detecting dark mode classes. - Dark Mode: The
darkMode: 'class'
setting ensures thedark
class on the<html>
element triggers dark mode styles.
- Verify CSS File Configuration
Tailwind CSS 4.0 uses a simplified CSS import. Check your main CSS file (e.g.,src/input.css
orstyles.css
):
@import 'tailwindcss';
- Unlike Tailwind CSS v3, you don’t need
@tailwind base
,@tailwind components
, or@tailwind utilities
. The single@import 'tailwindcss'
handles everything. - If you’re using custom styles, ensure they don’t conflict with Tailwind’s dark mode classes (e.g., overly specific selectors overriding
dark:
variants).
- Check PostCSS Configuration
Tailwind CSS 4.0 requires PostCSS to process the CSS. Ensure yourpostcss.config.js
is set up correctly:
module.exports = {
plugins: {
'@tailwindcss/postcss': {},
},
};
- Install PostCSS if missing:
bash npm install -D postcss
- If you’re using other PostCSS plugins (e.g.,
autoprefixer
), include them:javascript module.exports = { plugins: { '@tailwindcss/postcss': {}, autoprefixer: {}, }, };
- Build Process
Ensure you’re running the build process to generate the CSS output. For development, use:
npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch
- Input File: Matches your main CSS file (e.g.,
./src/input.css
). - Output File: Ensure the generated CSS (e.g.,
./dist/output.css
) is included in your HTML:html <link href="/dist/output.css" rel="stylesheet">
- For production, run a one-time build:
bash npx tailwindcss -i ./src/input.css -o ./dist/output.css
- If using a build tool like Vite, Webpack, or Next.js, ensure Tailwind is integrated correctly (see framework-specific setup below).
- HTML and JavaScript Setup
Ensure your HTML and JavaScript match the working CDN example. Here’s a minimal setup:
<!DOCTYPE html>
<html lang="en" class="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dark Mode Toggle</title>
<link href="/dist/output.css" rel="stylesheet">
</head>
<body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white min-h-screen flex items-center justify-center">
<div class="text-center">
<h1 class="text-3xl font-bold mb-4">Dark Mode Toggle</h1>
<button
onclick="document.documentElement.classList.toggle('dark'); document.documentElement.classList.toggle('light');"
class="px-4 py-2 bg-blue-500 dark:bg-blue-700 text-white rounded hover:bg-blue-600 dark:hover:bg-blue-800 transition"
>
Toggle Theme
</button>
</div>
</body>
</html>
- Dark Mode Classes: Ensure classes like
dark:bg-gray-900
are used correctly. - JavaScript Toggle: The
onclick
event togglesdark
andlight
classes on<html>
.
- Framework-Specific Setup
If you’re using a framework, ensure Tailwind is integrated properly:
- Vite:
- Install Vite and Tailwind:
bash npm create vite@latest my-project -- --template vanilla cd my-project npm install tailwindcss@latest @tailwindcss/postcss@latest postcss
- Update
vite.config.js
:javascript import { defineConfig } from 'vite'; export default defineConfig({ css: { postcss: './postcss.config.js', }, });
- Ensure
postcss.config.js
andtailwind.config.js
are set as above.
- Install Vite and Tailwind:
- Next.js:
- Create a new Next.js app:
bash npx create-next-app@latest my-app
- Tailwind CSS 4.0 is supported out of the box with Next.js 15+. Ensure
tailwind.config.js
hasdarkMode: 'class'
. - Use the CSS import in
app/globals.css
:css @import 'tailwindcss';
- Create a new Next.js app:
- React (with Vite or CRA):
- Ensure your
content
paths intailwind.config.js
include React files (e.g.,./src/**/*.{js,ts,jsx,tsx}
). - Verify the CSS file is imported in your app (e.g.,
import './index.css';
inindex.js
).
- Ensure your
- Common Issues and Fixes
- Dark Mode Classes Not Generated:
- Tailwind purges unused classes. Ensure
dark:
classes are used in your content files and included incontent
paths intailwind.config.js
. - Run
npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch
and check the output CSS fordark:
classes (e.g.,.dark\:bg-gray-900
).
- Tailwind purges unused classes. Ensure
- CSS Not Updating:
- Clear the build cache: Delete the
dist
folder and rebuild. - Ensure the
--watch
flag is used during development.
- Clear the build cache: Delete the
- Conflicting Styles:
- Check for global CSS overriding Tailwind’s styles. Use browser dev tools to inspect elements and verify
dark:
classes are applied. - If using third-party libraries, add
!important
to Tailwind classes if necessary (e.g.,dark:bg-gray-900!
).
- Check for global CSS overriding Tailwind’s styles. Use browser dev tools to inspect elements and verify
- Node.js Version:
- Tailwind CSS 4.0 requires Node.js 20 or higher. Check your version:
bash node -v
- Upgrade if needed:
bash nvm install 20 nvm use 20
- Tailwind CSS 4.0 requires Node.js 20 or higher. Check your version:
- Debugging
- Inspect Output CSS: Open
dist/output.css
and search for.dark\:bg-gray-900
or other dark mode classes. If missing, Tailwind isn’t detecting the classes in your content files. - Browser Dev Tools: Toggle the
dark
class on<html>
manually in the browser and check if styles apply. - Verbose Build: Run the build with verbose output:
bash npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch --verbose
Look for errors or warnings about missing content or misconfigured plugins.
- Persist Theme with
localStorage
If you’re usinglocalStorage
to persist the theme (as suggested in the CDN example), ensure the JavaScript is included:<script> if (localStorage.theme === 'dark' || (!localStorage.theme && window.matchMedia('(prefers-color-scheme: dark)').matches)) { document.documentElement.classList.add('dark'); document.documentElement.classList.remove('light'); } else { document.documentElement.classList.add('light'); document.documentElement.classList.remove('dark'); } function toggleTheme() { if (document.documentElement.classList.contains('dark')) { document.documentElement.classList.remove('dark'); document.documentElement.classList.add('light'); localStorage.theme = 'light'; } else { document.documentElement.classList.remove('light'); document.documentElement.classList.add('dark'); localStorage.theme = 'dark'; } } </script>
Update the button to useonclick="toggleTheme()"
.
Why It Works with CDN but Not npm
- CDN: The Tailwind CSS CDN includes the full framework with all utilities pre-generated, bypassing local configuration issues. It doesn’t rely on PostCSS, content scanning, or a build process.
- npm: Requires proper configuration (
tailwind.config.js
,postcss.config.js
, content paths) and a build step. Missteps in any of these can cause dark mode classes to be missing or not applied.
Example Project Setup
If the above doesn’t resolve the issue, try setting up a fresh project to isolate the problem:
mkdir tailwind-dark-mode
cd tailwind-dark-mode
npm init -y
npm install tailwindcss@latest @tailwindcss/postcss@latest postcss
npx tailwindcss init
Create postcss.config.js
:
module.exports = {
plugins: {
'@tailwindcss/postcss': {},
},
};
Update tailwind.config.js
:
module.exports = {
content: ["./src/**/*.{html,js}"],
darkMode: 'class',
theme: {
extend: {},
},
plugins: [],
};
Create src/input.css
:
@import 'tailwindcss';
Create src/index.html
:
<!DOCTYPE html>
<html lang="en" class="light">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dark Mode</title>
<link href="/dist/output.css" rel="stylesheet">
</head>
<body class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white min-h-screen flex items-center justify-center">
<div class="text-center">
<h1 class="text-3xl font-bold mb-4">Dark Mode Toggle</h1>
<button
onclick="document.documentElement.classList.toggle('dark'); document.documentElement.classList.toggle('light');"
class="px-4 py-2 bg-blue-500 dark:bg-blue-700 text-white rounded hover:bg-blue-600 dark:hover:bg-blue-800 transition"
>
Toggle Theme
</button>
</div>
</body>
</html>
Build and serve:
mkdir dist
npx tailwindcss -i ./src/input.css -o ./dist/output.css --watch
Use a local server (e.g., npx serve
or Vite) to test.
If It Still Doesn’t Work
- Share More Details: Provide your
tailwind.config.js
,postcss.config.js
, main CSS file, and how you’re running the build. Also, specify your framework (if any) and Node.js version. - Check for Errors: Look for errors in the terminal during the build or in the browser console.
- Compare with CDN: Since the CDN works, compare the generated CSS. The CDN’s CSS includes all
dark:
classes, so ensure your local build does too.
This should resolve most issues with dark mode not working in Tailwind CSS 4.0 with npm. If you hit a specific error, let me know, and I’ll dig deeper
-
Next Post
HTML Tutorial for Beginers