Dark Mode
Built-in dark mode with FOUC prevention and regression tests.
Setup
- Include
ThemeScriptbefore your content to prevent FOUC:
@layout.Base(layout.DefaultPageProps()) {
@layout.ThemeScript("")
{@content}
}
- Add the
@custom-variantdirective in your CSS:
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
- Optionally add a
ThemeToggle:
@layout.ThemeToggle("Toggle theme", "")
How It Works
ThemeScriptruns before first paint, readslocalStorage, and adds the.darkclass to<html>.color-scheme: lighton:root,color-scheme: darkon.dark— native form controls render correctly in both modes.ThemeTogglesyncs across all instances on the page viaquerySelectorAll.
Color Convention
| Context | Light | Dark |
|---|---|---|
| Semantic background | bg-blue-600 |
dark:bg-blue-500 |
| Semantic text | text-blue-600 |
dark:text-blue-400 |
| Neutral text | text-gray-500 |
dark:text-gray-400 |
Every neutral and semantic color class has a dark: variant — enforced by regression tests (TestDarkModeCompliance, TestDarkModeSemanticColors).
LocalStorage Guard
ThemeScript and ThemeToggle both wrap localStorage access in try/catch to handle Safari private mode (QuotaExceededError).
Last updated Edit this page