Skip to main content
The toggleTheme utility is a simple JavaScript function that toggles dark mode by adding or removing the dark class from the document root.

Overview

This utility provides a minimalist approach to theme switching, directly manipulating the DOM to toggle between light and dark modes. It’s used by the ButtonToggle component to enable dark mode functionality.

Source File

src/components/toggleTheme.jsx

Function Signature

const toggleTheme = () => void

Source Code

"use client";

const toggleTheme = () => {
    document.documentElement.classList.toggle('dark');
}

export default toggleTheme;

Usage

In React Components

Import and call the function on button click:
import toggleTheme from './toggleTheme.jsx';

function ThemeButton() {
  return (
    <button onClick={toggleTheme}>
      Toggle Theme
    </button>
  );
}

In Astro Components

Use with a client directive for interactivity:
---
import ButtonToggle from '../components/buttonToggle.jsx';
---

<ButtonToggle client:load />

How It Works

The function uses the DOM classList.toggle() method to add or remove the dark class from document.documentElement (the <html> element).
1

Initial state

When the page loads, the <html> element has no dark class, so light mode styles apply.
2

First toggle

Calling toggleTheme() adds the dark class to <html>, activating dark mode styles defined with the .dark selector.
3

Second toggle

Calling toggleTheme() again removes the dark class, reverting to light mode.

CSS Integration

The function works in conjunction with CSS that uses the .dark selector. For example, from src/styles/global.css:
/* Light mode (default) */
body {
    background: #ffffff;
}

/* Dark mode */
.dark body {
    background: #191919;
}
Or with the custom dark variant in Tailwind CSS v4:
@custom-variant dark (&:where(.dark, .dark *));

Client Directive

The "use client" directive at the top of the file indicates this code should only run in the browser (client-side), not during server-side rendering.
"use client";
This is important because:
  • document is only available in the browser
  • Server-side rendering would fail if trying to access document.documentElement

Limitations

This utility does not persist the theme preference. When the page reloads, the theme resets to light mode.

No Persistence

The current implementation doesn’t save the user’s theme choice. Each page load starts in light mode regardless of the user’s previous selection.

No System Preference Detection

The utility doesn’t check the user’s system-level dark mode preference (prefers-color-scheme).

Enhancement Ideas

Save the theme preference so it persists across page loads:
"use client";

const toggleTheme = () => {
    const html = document.documentElement;
    html.classList.toggle('dark');
    
    // Save preference
    const isDark = html.classList.contains('dark');
    localStorage.setItem('theme', isDark ? 'dark' : 'light');
}

// On page load, restore saved preference
if (typeof window !== 'undefined') {
    const savedTheme = localStorage.getItem('theme');
    if (savedTheme === 'dark') {
        document.documentElement.classList.add('dark');
    }
}

export default toggleTheme;
Initialize theme based on user’s system preference:
"use client";

const toggleTheme = () => {
    document.documentElement.classList.toggle('dark');
}

// Initialize based on system preference
if (typeof window !== 'undefined') {
    const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
    if (prefersDark) {
        document.documentElement.classList.add('dark');
    }
}

export default toggleTheme;
Make the function return the new theme state:
"use client";

const toggleTheme = () => {
    const html = document.documentElement;
    html.classList.toggle('dark');
    return html.classList.contains('dark') ? 'dark' : 'light';
}

export default toggleTheme;
This allows components to update their UI based on the current theme.
Prevent jarring color changes with CSS transitions:
"use client";

const toggleTheme = () => {
    const html = document.documentElement;
    
    // Add transition class before toggle
    html.style.transition = 'background-color 0.3s ease';
    
    html.classList.toggle('dark');
    
    // Remove transition after it completes
    setTimeout(() => {
        html.style.transition = '';
    }, 300);
}

export default toggleTheme;

Browser Compatibility

The function uses standard DOM APIs that are supported in all modern browsers:
  • document.documentElement - IE9+
  • classList.toggle() - IE10+ (with polyfill for IE9)
For IE9 support, you may need a classList polyfill. Modern browsers (Chrome, Firefox, Safari, Edge) support this natively.

Usage in Chitagá Tech

In the Chitagá Tech project, this utility is imported by the ButtonToggle component:
// src/components/buttonToggle.jsx
import React, { useState } from "react";
import { MdDarkMode, MdLightMode } from "react-icons/md";
import toggleTheme from "./toggleTheme";

export default function ButtonToggle() {
  const [isDarkMode, setIsDarkMode] = useState(false);

  const handleToggleTheme = () => {
    toggleTheme();
    setIsDarkMode(!isDarkMode);
  };

  return (
    <button id="toggle-theme" onClick={handleToggleTheme}>
      {isDarkMode ? <MdLightMode size={20} /> : <MdDarkMode size={20} />}
    </button>
  );
}

Testing

To test the utility:
  1. Open your browser’s developer console
  2. Run: document.documentElement.classList.contains('dark')
  3. Should return false initially
  4. Click the theme toggle button
  5. Run the same command again - should return true
  6. Reload the page - returns to false (no persistence)

ButtonToggle Component

React component that uses this utility

Styling Guide

Learn about the dark mode CSS implementation

Global Styles

See how dark mode styles are defined

Build docs developers (and LLMs) love