Dark Mode
Velocity includes automatic dark mode with system preference detection and manual toggle.
How It Works
Section titled “How It Works”- On page load, checks
localStoragefor saved preference - Falls back to system preference (
prefers-color-scheme) - Adds/removes
.darkclass on<html> - All semantic tokens automatically switch values
Theme Toggle Component
Section titled “Theme Toggle Component”---import ThemeToggle from '@/components/layout/ThemeToggle.astro';---
<ThemeToggle />The toggle:
- Cycles through: System → Light → Dark
- Persists choice in
localStorage - Updates immediately without flash
Token Switching
Section titled “Token Switching”Semantic tokens swap values automatically:
/* Light mode (default) */:root { --background: var(--gray-0); /* White */ --foreground: var(--gray-900); /* Near black */}
/* Dark mode */.dark { --background: var(--gray-950); /* Near black */ --foreground: var(--gray-50); /* Near white */}Preventing Flash
Section titled “Preventing Flash”The theme is initialized in <head> before page render:
<script is:inline> const theme = localStorage.getItem('theme'); const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
if (theme === 'dark' || (!theme && prefersDark)) { document.documentElement.classList.add('dark'); }</script>Manual Control
Section titled “Manual Control”JavaScript API
Section titled “JavaScript API”// Check current themeconst isDark = document.documentElement.classList.contains('dark');
// Set dark modedocument.documentElement.classList.add('dark');localStorage.setItem('theme', 'dark');
// Set light modedocument.documentElement.classList.remove('dark');localStorage.setItem('theme', 'light');
// Follow systemlocalStorage.removeItem('theme');// Then check prefers-color-schemeCSS Targeting
Section titled “CSS Targeting”/* Target dark mode specifically */.dark .my-component { /* Dark mode styles */}
/* Or use Tailwind's dark: modifier */<div class="bg-white dark:bg-gray-900">Component Patterns
Section titled “Component Patterns”Conditional Rendering
Section titled “Conditional Rendering”---// Server-side: use client hint or defaultconst theme = Astro.request.headers.get('Sec-CH-Prefers-Color-Scheme');---
<!-- Client-side: check class --><script> const isDark = document.documentElement.classList.contains('dark');</script>Color Scheme Props
Section titled “Color Scheme Props”Many components accept a colorScheme prop:
<!-- Automatic (follows theme) --><Button>Default</Button>
<!-- Force inverted colors (for dark backgrounds) --><Button colorScheme="invert">On Dark</Button>Inverted Sections
Section titled “Inverted Sections”For dark sections on light pages, use inverted tokens:
<section class="bg-surface-invert"> <h2 class="text-on-invert">Title</h2> <p class="text-on-invert-muted">Description</p> <Button colorScheme="invert">CTA</Button></section>This works in both light and dark mode, maintaining proper contrast.