Dark Mode Implementation
3
Upvotes
51
Views
6
Downloads
777
Words
Description
Implements theme switching with CSS custom properties, system preference detection, and persistence for reliable dark/light modes.
When to Use
How do I implement dark mode with CSS variables? | Show me how to add a theme toggle with system preference. | I want to persist theme across tabs using localStorage. | How can I detect system color scheme and apply it?
Use Cases
Add a system-aware theme toggle in a web app. | Persist user theme in localStorage across sessions. | Prevent flash of incorrect theme on initial load. | Ensure images and icons adapt to the current theme.
SKILL.md Content
---
name: dark-mode-implementation
description: "Implements theme switching with CSS custom properties, system preference detection, and persistence for reliable dark/light modes."
metadata:
tags: "frontend, ui-theming, dark-mode, css-variables, prefers-color-scheme, localstorage, theme-toggle, accessibility"
source: "https://skilldb.dev/skills/autonomous-agent-skills/dark-mode-implementation"
pack: "autonomous-agent-skills"
category: "Autonomous Agents"
---
# Dark Mode Implementation
## When to use this skill
Use when the user says things like:
- "How do I implement dark mode with CSS variables?"
- "Show me how to add a theme toggle with system preference."
- "I want to persist theme across tabs using localStorage."
- "How can I detect system color scheme and apply it?"
You are an AI agent that implements theme switching correctly. You use CSS custom properties for theming, detect system preferences, persist user choices, prevent flash of wrong theme, and ensure all visual elements adapt properly including images and icons.
## Philosophy
Dark mode is not just inverting colors. It is a complete design system concern that touches every visual element in the application. A proper implementation respects user preferences, transitions smoothly, persists across sessions, and never flashes the wrong theme on load. It must work from the CSS level to the image level, with every component aware of the current theme.
## Techniques
### Use CSS Custom Properties for Theming
- Define all colors as CSS custom properties on `:root` or a theme class.
- Switch themes by changing the values of these properties.
- Organize properties semantically: `--color-background`, `--color-text-primary`, not `--white`, `--black`.
- Include properties for surfaces, borders, shadows, and interactive states.
- Use a naming convention that describes purpose, not appearance.
```css
:root {
--color-bg-primary: #ffffff;
--color-text-primary: #1a1a1a;
--color-border: #e0e0e0;
}
[data-theme="dark"] {
--color-bg-primary: #1a1a1a;
--color-text-primary: #e0e0e0;
--color-border: #333333;
}
```
### Detect System Preferences
- Use the `prefers-color-scheme` media query to detect the OS setting.
- In CSS: `@media (prefers-color-scheme: dark) { ... }`.
- In JavaScript: `window.matchMedia('(prefers-color-scheme: dark)')`.
- Listen for changes with `matchMedia.addEventListener('change', callback)`.
- Use the system preference as the default when no user preference is stored.
### Persist Theme Choice
- Store the user's theme preference in localStorage.
- Check localStorage before rendering to apply the correct theme immediately.
- Provide three options: Light, Dark, System (follow OS preference).
- Sync the preference across tabs using the `storage` event.
- Fall back to system preference when no stored preference exists.
### Prevent Flash of Wrong Theme
- Apply the theme in a blocking script in the `<head>` before any rendering.
- Read localStorage synchronously and set the theme attribute on `<html>` immediately.
- Do not rely on React/framework hydration to set the theme, as it happens too late.
- For server-rendered pages, use cookies to send the theme preference with the request.
- This script must be inline, not in an external file that requires a network request.
### Adapt Images and Icons for Themes
- Use `filter: invert(1)` for simple icon color inversion.
- Provide separate image assets for light and dark themes when inversion is not sufficient.
- Use `<picture>` with `<source media="(prefers-color-scheme: dark)">` for theme-aware images.
- SVG icons should use `currentColor` to inherit the text color.
- Adjust image brightness and contrast in dark mode to reduce eye strain.
### Implement Smooth Theme Transitions
- Add a CSS transition on color properties: `transition: color 0.2s, background-color 0.2s`.
- Apply the transition class temporarily during theme switch, then remove it.
- Do not apply transitions on page load to prevent initial animation.
- Keep transitions short (150-200ms) to feel responsive.
- Transition only color-related properties to avoid layout thrashing.
### Handle Component-Level Theme Awareness
- Third-party components may need explicit theme configuration.
- Code syntax highlighting themes must switch with the application theme.
- Charts and data visualizations need theme-aware color palettes.
- Map and embed components may have their own theme APIs.
- Test every component in both themes to catch hardcoded colors.
## Best Practices
1. Design the dark theme intentionally, not by just inverting the light theme.
2. Use slightly lower contrast in dark mode to reduce eye strain (not pure white on pure black).
3. Reduce shadow intensity in dark mode; use lighter borders or subtle glows instead.
4. Test both themes at every stage of development, not as an afterthought.
5. Ensure sufficient contrast ratios (WCAG AA: 4.5:1 for text) in both themes.
6. Include the theme toggle in an easily accessible location.
7. Test the theme toggle rapidly to verify transitions are smooth and state is correct.
## Anti-Patterns
- **Hardcoded colors**: Using `color: #333` instead of `color: var(--color-text-primary)` throughout the codebase.
- **Flash of light theme**: Page loads in light mode and then switches to dark, causing a white flash.
- **Forgotten components**: Most of the app supports dark mode, but some pages or modals do not.
- **Pure black backgrounds**: Using `#000000` for dark mode backgrounds, which creates excessive contrast.
- **Opacity for darkening**: Using opacity to darken elements, which also makes them transparent.
- **Lost preference**: User sets dark mode, refreshes, and sees light mode briefly before it switches.
- **No system option**: Forcing users to manually toggle instead of following their OS preference.
- **Invisible elements**: Icons or borders that disappear against the dark background because they were designed only for light mode.