TT5 Dark Mode

Add dark / light mode switching to WordPress Twenty Twenty-Five — plus global focus fixes, shadow presets, and link hover customization.


Overview

TT5 Dark Mode is a companion plugin for the WordPress Twenty Twenty-Five theme. It adds what the stock theme is missing:

ProblemSolution
No way for visitors to switch between dark and light modeCookie-persisted toggle with zero FOUC
Crude :focus outlines (no color, no offset, no :focus-visible)Comprehensive, customizable focus system
Broken var:preset|shadow|natural reference in Noon variationShadow presets injected via wp_theme_json_data_theme
Link hover only changes underline to dotted — no color or animationConfigurable hover color, underline style, and transition

Everything is managed through a tabbed settings panel under Settings → TT5 Dark Mode.

Features

Dark / Light Mode

  • Two-state toggle — Dark ↔ Light (default).
  • Three-state cycle — Auto → Dark → Light, honoring prefers-color-scheme.
  • Four official palettes — Evening, Twilight, Midnight, Sunrise.
  • Smart inversion — Automatically provides a light-mode switch when the active style variation is already dark.
  • Zero FOUC — Inline <head> script reads the cookie before first paint.
  • Cookie persistencett5dm_pref, SameSite=Lax, Secure flag on HTTPS.

Gutenberg Blocks

BlockDescription
Dark Mode ToggleStyleable button (pill / icon-only / switch). Full block support: color, spacing, typography, border.
Mode-Aware ContentContainer that shows its children only in dark or light mode. Pure CSS — no JS on the frontend.

Block Patterns: Header with Toggle · Mode-Aware Hero Section · Mode-Aware Logo

Focus & Outline System

  • Global :focus-visible with color, width, style, and offset controls.
  • Element-level overrides for buttons, form inputs, and navigation.
  • Separate outline color for dark mode.
  • Three modes: focus-visible (recommended) / focus / disabled.

Box Shadow Presets

  • Natural, Soft, and Hard presets — appear in the Gutenberg Shadow picker.
  • Fixes the broken var:preset|shadow|natural reference.
  • Dark mode adjustment: Inherit / Darken / Glow.

Link & Hover

  • Hover color, underline style, transition duration (0–1000 ms).
  • Button hover opacity via color-mix().

Custom CSS

  • Inject arbitrary CSS with mode-specific selectors (html.tt5-dark-mode, html.tt5-light-mode).

Installation

From ZIP

  1. Download the latest release .zip file.
  2. In WordPress, go to Plugins → Add New → Upload Plugin and upload the zip.
  3. Activate the plugin.

Manual

cd wp-content/plugins/
git clone https://github.com/satoshiwp/tt5-dark-mode.git

Activate through the WordPress admin.

Configuration

  1. Settings → TT5 Dark Mode — Configure palette, focus, shadows, links, and custom CSS.
  2. Site Editor → Header template — Insert the Dark Mode Toggle block.

Architecture

index.php (main plugin file)
│
├── [FOUC inline script]      ← <head> priority 1, reads cookie, sets html class
│
├── [Frontend CSS]            ← wp_add_inline_style: palette + focus + links + custom
│
├── [Shadow presets]          ← wp_theme_json_data_theme → Gutenberg Shadow picker
│
├── dark-mode-core.js         ← Singleton state manager, loaded on-demand via viewScript
│   └── view.js               ← Toggle block frontend interactivity
│
├── blocks/toggle/            ← Dark Mode Toggle Gutenberg block
│   ├── block.json
│   ├── edit.js               ← Editor component (no build step, raw createElement)
│   ├── render.php            ← Server-side render (<button> = block root)
│   ├── view.js               ← Frontend JS (depends on core.js)
│   ├── style.css             ← Shared styles
│   └── editor.css            ← Editor-only styles
│
├── blocks/mode-content/      ← Mode-Aware Content Gutenberg block
│   ├── block.json
│   ├── edit.js
│   ├── render.php
│   ├── style.css             ← Pure CSS visibility switching
│   └── editor.css
│
├── assets/css/admin.css      ← Admin settings page styles
├── assets/js/admin.js        ← Tab switching, color swatches, shadow preview
│
└── includes/blocks.php       ← Block registration, patterns, editor data injection

For Developers

Filters

// Customize the dark palette programmatically
add_filter( 'tt5dm_dark_palette', function ( $palette, $selected_key ) {
    $palette['colors']['accent-1'] = '#FF6600';
    return $palette;
}, 10, 2 );

CSS Custom Properties

/* Global focus variables (set by plugin settings) */
:root {
    --tt5c-focus-color:  #007cba;
    --tt5c-focus-width:  2px;
    --tt5c-focus-style:  solid;
    --tt5c-focus-offset: 2px;
}

/* Toggle-specific focus variables (override per-block) */
:root {
    --tt5dm-focus-color:  currentColor;
    --tt5dm-focus-width:  2px;
    --tt5dm-focus-offset: 2px;
}

JavaScript API

// The global state object (available after core.js loads)
window.__tt5dm.getPref();       // 'auto' | 'dark' | 'light'
window.__tt5dm.isDark();        // boolean — current computed state
window.__tt5dm.cycle();         // Advance to next preference
window.__tt5dm.apply('dark');   // Set a specific preference

// Listen for changes
document.addEventListener('tt5dm:change', (e) => {
    console.log(e.detail.pref);   // 'auto' | 'dark' | 'light'
    console.log(e.detail.isDark); // boolean
});

Mode-Specific CSS Selectors

html.tt5-dark-mode  { /* dark mode active  */ }
html.tt5-light-mode { /* light mode active */ }

/* Example: different background image per mode */
html.tt5-dark-mode .hero  { background-image: url(hero-dark.jpg); }
html.tt5-light-mode .hero { background-image: url(hero-light.jpg); }

Requirements

RequirementVersion
WordPress6.7+
PHP7.4+
ThemeTwenty Twenty-Five (or child theme)

Technical Details

  • No build step — Editor scripts use wp.element.createElement directly.
  • No dependencies — No jQuery, no external frameworks.
  • Under 8 KB total — All files combined.
  • Inline CSS only — Zero extra HTTP requests for styles.
  • Full i18n — All strings use the tt5-dark-mode text domain.
  • WordPress Coding Standards — Follows WPCS conventions.

License

This project is licensed under the GNU General Public License v2.0 or later.


TT5 Dark Mode — Making Twenty Twenty-Five comfortable at any hour.