Implementing a Dark/Light Theme Switch on a Jekyll Site

Published on August 25, 2025

This is how I implemented a simple dark/light theme toggle on my Jekyll site using Tailwind CSS and vanilla JavaScript. The approach is lightweight, straightforward, and easily adaptable for personal or portfolio websites built with Jekyll.

Configuring Tailwind CSS Dark Mode Class

I configured Tailwind CSS to support dark mode by adding the following code in the tailwind.config.js file:

module.exports = {
  darkMode: 'class', // Enable dark mode with a class
  theme: {
    extend: {},
  },
  plugins: [],
}

With this setup, the dark mode styles will be applied when a dark class is added to the <html> element.

Adding the Toggle in HTML

I used a simple link to toggle between dark and light modes. The icon displayed on the button changes depending on the current theme (e.g. a sun for light mode and a moon for dark mode).

<a href="#" onclick="switchTheme()" class="flex items-center">
  <span class="inline-flex dark:hidden">
    <!-- Light Mode Icon (Sun) -->
    <svg viewBox="0 0 24 24" fill="none" class="w-6 h-6">
      <!-- SVG paths for the light icon -->
    </svg>
  </span>
  <span class="hidden dark:inline-flex">
    <!-- Dark Mode Icon (Moon) -->
    <svg viewBox="0 0 24 24" fill="none" class="w-6 h-6">
      <!-- SVG paths for the dark icon -->
    </svg>
  </span>
</a>

In the above code, the dark:hidden class hides the light mode icon in dark mode, and dark:inline-flex shows the dark mode icon when the theme is set to dark.

Implementing the JS function for Theme Toggling

Next, I wrote a small JavaScript function to toggle between light and dark modes. It uses localStorage to persist the theme selection even after a page reload.

function switchTheme() {
    if (localStorage.theme === 'light' || !('theme' in localStorage)) {
        localStorage.theme = 'dark';
        document.documentElement.classList.add('dark');
        return;
    }

    localStorage.theme = 'light';
    document.documentElement.classList.remove('dark');
}

// Apply saved theme on page load
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');
}

This function checks for the stored theme in localStorage, applies the corresponding theme, and updates the icon. On page load, it checks the saved theme and applies it, or defaults to the user’s system preference if no theme is saved.

Using Tailwind CSS Styling for Dark Mode

Tailwind’s dark: variant makes it easy to define styles that change when dark mode is enabled.

<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-white">
  <!-- Content goes here -->
</div>

Avoiding FOUC and Ensuring Persistence

To make sure the theme persists across page reloads, localStorage was used to save the theme. The JavaScript function checks for the saved theme and applies it when the page is loaded. This avoids any flash of unstyled content (FOUC) when switching themes.

To ensure that the page doesn’t render the wrong theme before the script runs, I added the script early in the <head> of the HTML:

<head>
  <!-- Theme switcher script -->
  <script type="text/javascript" src="/assets/js/theme-switcher.js"></script>
  <!-- Other head content -->
</head>