Dark Mode

The New CSS supports dark mode out of the box using a gray token swapping approach. No extra classes are needed -- your existing bg-gray-* and text-gray-* utilities automatically adapt.

How It Works

Instead of adding separate dark-prefixed utilities, The New CSS inverts the gray scale when dark mode is active. The CSS custom properties for gray colors are remapped so that light values become dark and vice versa:

TokenLight ModeDark Mode
--color-gray-50Near white (0.985)Near black (0.13)
--color-gray-100Very light (0.97)Very dark (0.17)
--color-gray-200Light (0.92)Dark (0.22)
--color-gray-500Mid (0.55)Mid (0.55)
--color-gray-900Near black (0.21)Near white (0.92)
--color-gray-950Darkest (0.13)Lightest (0.97)

This means bg-white text-gray-900 on your <body> gives a white background with dark text in light mode, and automatically flips to a dark background with light text in dark mode.

Activation Methods

1. Automatic (OS Preference)

Dark mode activates automatically when the user's OS is set to dark mode, using @media (prefers-color-scheme: dark). No JavaScript required.

The automatic mode respects an opt-out: if data-theme="light" is set on <html>, dark mode will not apply even if the OS prefers it.

<!-- Automatic: follows OS preference (default behavior) --> <html lang="en"> <!-- Force light mode regardless of OS --> <html lang="en" data-theme="light">

2. Manual (data-theme attribute)

Force dark mode by adding data-theme="dark" to any element (typically <html>). This activates dark mode regardless of OS preference.

<!-- Force dark mode --> <html lang="en" data-theme="dark">

Toggle Button

Implement a theme toggle with a small script. This example cycles between auto, light, and dark, persisting the choice in localStorage:

<button id="theme-toggle" class="p-2 rounded-lg hover:bg-gray-100"> Toggle Theme </button> <script> const btn = document.getElementById('theme-toggle'); const html = document.documentElement; // Restore saved preference const saved = localStorage.getItem('theme'); if (saved) html.setAttribute('data-theme', saved); btn.addEventListener('click', () => { const current = html.getAttribute('data-theme'); let next; if (!current) next = 'dark'; else if (current === 'dark') next = 'light'; else { next = null; } if (next) { html.setAttribute('data-theme', next); localStorage.setItem('theme', next); } else { html.removeAttribute('data-theme'); localStorage.removeItem('theme'); } }); </script>

Swapped Tokens Reference

All eleven gray tokens are swapped in dark mode. The color-scheme: dark property is also set, which tells the browser to use dark form controls, scrollbars, and other native UI elements.

TokenDark Value (oklch)
--color-gray-50oklch(0.13 0.005 260)
--color-gray-100oklch(0.17 0.007 260)
--color-gray-200oklch(0.22 0.009 260)
--color-gray-300oklch(0.31 0.012 260)
--color-gray-400oklch(0.45 0.014 260)
--color-gray-500oklch(0.55 0.014 260)
--color-gray-600oklch(0.71 0.01 260)
--color-gray-700oklch(0.79 0.008 260)
--color-gray-800oklch(0.87 0.006 260)
--color-gray-900oklch(0.92 0.004 260)
--color-gray-950oklch(0.97 0.001 260)

Examples

Card that adapts automatically

This card uses standard gray utilities. Toggle your OS dark mode (or use the button in the nav) to see it adapt with no extra classes:

Adaptive Card

This text and background swap automatically in dark mode via token remapping.

Tag
<div class="p-6 bg-gray-50 border border-gray-200 rounded-lg"> <h4 class="font-semibold text-gray-900 mb-1">Adaptive Card</h4> <p class="text-gray-600 text-sm mb-3">Swaps automatically in dark mode.</p> <span class="inline-block px-3 py-1 bg-gray-200 text-gray-700 rounded-full text-xs font-medium">Tag</span> </div>

Side-by-side comparison

Use data-theme on individual elements to force a theme within a region:

Light Mode

data-theme="light"

Dark Mode

data-theme="dark"

<div class="grid grid-cols-1 md:grid-cols-2 gap-4"> <div data-theme="light" class="p-4 bg-gray-50 rounded-lg"> <p class="font-semibold text-gray-900">Light Mode</p> </div> <div data-theme="dark" class="p-4 bg-gray-50 rounded-lg"> <p class="font-semibold text-gray-900">Dark Mode</p> </div> </div>