How to Add Dark Mode to Your Website Using Tailwind CSS (Clean & Fast)

April 9, 2026
Link copied!
How to Add Dark Mode to Your Website Using Tailwind CSS (Clean & Fast)

Dark mode is no longer just a trend, it has become a standard feature in modern web design. Many users today prefer either light or dark mode depending on their environment, device settings, or personal comfort.

Adding this feature to your website not only improves user experience, but also makes your project feel more professional, especially if you’re showcasing it in your portfolio.

In this guide, you’ll learn how to implement a clean and performant dark/light mode toggle using Tailwind CSS and a bit of JavaScript.

Why You Should Add Dark Mode?

  • Improves user experience
  • Gives users control over their preferences
  • Enhances your portfolio projects
  • Looks modern and polished
  • Can be implemented without affecting performance

Step 1 : Configure Tailwind for Dark Mode

After installing Tailwind CSS locally, add this custom variant to your main CSS file :

@custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *));

Step 2 : Apply Saved Theme Automatically

We want the website to remember the user’s choice using localStorage.

function applyTheme() {
  const savedTheme = localStorage.getItem('theme') || 'light';
  document.documentElement.setAttribute('data-theme', savedTheme);
}

window.addEventListener('pageshow', (event) => {
  if (event.persisted) {
    applyTheme();
  }
});

document.addEventListener('DOMContentLoaded', applyTheme);

This ensures :

  • The theme is applied on first load
  • It persists across page navigation
  • Works even with browser cache (important detail!)

Step 3: Create a Dropdown Toggle for Theme Switching

In this example, instead of using a simple button, we’re creating a dropdown menu that lets users choose between light and dark mode.

This approach improves UX because it :

  • Makes the options clearer (instead of just toggling blindly)
  • Looks more modern and interactive
  • Gives you more flexibility (you can add more themes later if needed)

HTML Structure :

We wrap everything inside a parent container with the ID btn-toggle-mode. This acts as the clickable trigger for the dropdown.

Inside it :

  • The icon (sun/moon) shows the current mode
  • The dropdown menu contains the theme options
<div class="relative" id="btn-toggle-mode">

  <!-- Icon -->
  <div class="hover:bg-[#FFF8E6] dark:hover:bg-[#1E1C30]
   p-2 duration-300 cursor-pointer rounded-sm block">
    
    <!-- Light icon -->
    <div class="dark:hidden inline">
      <i class="fas fa-lg fa-sun text-[#FFD473]"></i>
    </div>

    <!-- Dark icon -->
    <div class="dark:inline hidden">
      <i class="fas fa-lg fa-moon text-[#8156F5]"></i>
    </div>

  </div>

  <!-- Dropdown -->
  <div class="dropdown-dark-light hidden absolute w-40 
   pt-3 pb-3 px-3 rounded-lg duration-300
   bg-white dark:bg-[hsl(221,14%,9%)]
   border border-[hsl(221,14%,86%)] dark:border-[hsl(221,14%,24%)]">

    <button onclick="setTheme('light')" class="w-full text-left px-4 py-2">
      <i class="fas fa-sun text-[#FFD473]"></i> Light Mode
    </button>

    <button onclick="setTheme('dark')" class="w-full text-left px-4 py-2">
      <i class="fas fa-moon text-[#8156F5]"></i> Dark Mode
    </button>

  </div>
</div>

JavaScript Logic :

Now we handle the dropdown behavior.

const toggleMode = document.querySelector("#btn-toggle-mode");
const dropdown = document.querySelector(".dropdown-dark-light");

toggleMode.addEventListener("click", (e) => {
  if (!dropdown.contains(e.target)) {
    dropdown.classList.toggle("hidden");
  }
});

How It Works :

  • When the user clicks on the container (#btn-toggle-mode), we toggle the dropdown visibility.
  • The condition !dropdown.contains(e.target) ensures : 1. Clicking the icon opens/closes the dropdown, 2. Clicking inside the dropdown (on buttons) doesn’t instantly re-toggle it

Pro Improvement (Recommended)

To make it feel more polished, you can also close the dropdown when clicking outside :

document.addEventListener("click", (e) => {
  if (!toggleMode.contains(e.target)) {
    dropdown.classList.add("hidden");
  }
});

Step 4 : Save and Apply the Selected Theme

Now that the user can open the dropdown and choose a mode, we need to actually apply and store the selection.

function setTheme(mode) {
  document.documentElement.setAttribute('data-theme', mode);
  localStorage.setItem('theme', mode);
}

What This Does :

  • Updates the data-theme attribute on the element
  • Saves the user’s preference in localStorage
  • Ensures the choice is remembered on future visits

Step 5 : Set a Default Theme

Don’t forget to define a default theme directly in your HTML :

<html data-theme="light">

Step 6 : Use Dark Mode in Tailwind

Now comes the easiest (and most satisfying) part.

With your setup, you can use Tailwind’s dark: modifier to style elements differently depending on the theme :

<div class="border-gray-200 dark:border-gray-700 
            bg-gray-100 hover:bg-gray-200 
            dark:bg-gray-500 dark:hover:bg-gray-600">
</div>

Tip :

Think of dark: as an override. You write your normal styles first, then adjust only what changes in dark mode.

Step 7 : Handling Special Cases (Images & Assets)

Sometimes CSS alone isn’t enough, However, in some cases like logos, you can handle everything cleanly using Tailwind without any JavaScript.

For example, if you have two versions of your logo (one for light mode and one for dark mode), you can simply toggle their visibility using Tailwind’s dark: utility :

<a class="logo" href="/">

  <!-- Light logo -->
  <img
    class="block dark:hidden w-full max-w-40 sm:max-w-70"
    src="light-logo.png"
    alt="Logo">

  <!-- Dark logo -->
  <img
    class="hidden dark:block w-full max-w-40 sm:max-w-70"
    src="dark-logo.png"
    alt="Logo dark mode">

</a>

Why This Works :

  • dark:hidden hides the light logo in dark mode
  • dark:block shows the dark logo only when dark mode is active
  • No JavaScript is required
  • Keeps your implementation simple and performant

Tip

Try to rely on CSS whenever possible. Use JavaScript only when you truly need dynamic behavior. This keeps your code cleaner and improves performance.

Common Mistakes to Avoid

This section is very important for SEO (Google loves this kind of content) :

  • ❌ Using data-theme=”white” → always use light
  • ❌ Overcomplicating logic with too much JavaScript
  • ❌ Forgetting to load the saved theme on page load
  • ❌ Not handling cached pages (pageshow event which you did ✔️)

Final Thoughts

Dark mode is a small feature with a big impact. It improves usability, gives users more control, and makes your projects feel modern and complete.

The key is to keep your implementation :

  • Simple
  • Performant
  • Easy to maintain

With just Tailwind CSS and a few lines of JavaScript, you now have a fully functional and scalable theme system.