How It Works
Tabule Theme's dark mode is a full alternative color scheme that visitors can toggle on demand. It is designed to load instantly — without any flash of the wrong color — and to remember the visitor's preference between page loads and browser sessions.
The anti-FOUC script
The most important part of the dark mode implementation is an inline <script> injected into <head> at the very highest priority (before any CSS loads). This script runs synchronously, which means it completes before the browser paints anything.
What the script does:
- Reads
localStorage.getItem("tbl-color-scheme")to check if the visitor has a saved preference. - If a preference exists, it sets
document.documentElement.setAttribute("data-theme", "dark" | "light")immediately. - If no preference exists, it falls back to the Default Mode setting configured in the Customizer — either a fixed light or dark, or the system's
prefers-color-schememedia query.
Because this runs before CSS, the page renders in the correct theme on the very first paint. Visitors never see a white flash before dark mode activates.
CSS architecture
Dark mode styles live in a separate dark-mode.css file that is only enqueued when dark mode is enabled in the Customizer. It uses the [data-theme="dark"] attribute selector on the <html> element to override all relevant CSS custom properties and colors.
Toggle button
When the toggle button is enabled, dark-mode.js is loaded with the defer attribute. The script handles click events on the toggle button. When clicked, it:
- Flips the
data-themeattribute on<html>. - Saves the new preference to
localStorageastbl-color-scheme.
Priority of preference resolution
- Visitor's saved preference in
localStorage(from a previous manual toggle) — highest priority. - Customizer Default Mode: Always Dark or Always Light.
- Customizer Default Mode: Follow system preference — uses the browser's
prefers-color-scheme: darkmedia query.
No cookies, no server-side logic
The preference is stored entirely in localStorage. No cookies are set and no server-side state is involved. This means the dark mode choice does not affect caching and does not require any consent banner entry for GDPR purposes.