403 words
2 minutes
Dark Mode Implementation Guide

Dark Mode Implementation#

Dark mode isn’t just black backgrounds. It’s an art form.

CSS Variables Approach#

Base Setup#

:root {
/* Light mode (default) */
--bg-primary: #ffffff;
--bg-secondary: #f5f5f5;
--text-primary: #1a1a1a;
--text-secondary: #666666;
--accent: #3b82f6;
--border: #e5e5e5;
}
[data-theme="dark"] {
--bg-primary: #0a0a0a;
--bg-secondary: #171717;
--text-primary: #ffffff;
--text-secondary: #a3a3a3;
--accent: #60a5fa;
--border: #262626;
}
body {
background-color: var(--bg-primary);
color: var(--text-primary);
transition: background-color 0.3s, color 0.3s;
}

Usage#

.card {
background: var(--bg-secondary);
border: 1px solid var(--border);
color: var(--text-primary);
}
.button {
background: var(--accent);
color: white;
}
.muted {
color: var(--text-secondary);
}

JavaScript Toggle#

const toggle = document.getElementById('theme-toggle');
const html = document.documentElement;
// Check for saved preference or system preference
const getTheme = () => {
const saved = localStorage.getItem('theme');
if (saved) return saved;
return window.matchMedia('(prefers-color-scheme: dark)').matches
? 'dark'
: 'light';
};
// Apply theme
const setTheme = (theme) => {
html.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
};
// Initialize
setTheme(getTheme());
// Toggle
toggle.addEventListener('click', () => {
const current = html.getAttribute('data-theme');
setTheme(current === 'dark' ? 'light' : 'dark');
});

React Implementation#

import { useState, useEffect, createContext, useContext } from 'react';
const ThemeContext = createContext();
export function ThemeProvider({ children }) {
const [theme, setTheme] = useState('light');
useEffect(() => {
const saved = localStorage.getItem('theme');
if (saved) {
setTheme(saved);
} else if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
setTheme('dark');
}
}, []);
useEffect(() => {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('theme', theme);
}, [theme]);
const toggle = () => setTheme(theme === 'dark' ? 'light' : 'dark');
return (
<ThemeContext.Provider value={{ theme, toggle }}>
{children}
</ThemeContext.Provider>
);
}
export const useTheme = () => useContext(ThemeContext);

Theme Toggle Button#

function ThemeToggle() {
const { theme, toggle } = useTheme();
return (
<button onClick={toggle} aria-label="Toggle theme">
{theme === 'dark' ? 'Light' : 'Dark'}
</button>
);
}

Tailwind CSS Dark Mode#

tailwind.config.js
module.exports = {
darkMode: 'class', // or 'media'
}
<div className="bg-white dark:bg-gray-900">
<p className="text-gray-900 dark:text-white">
Hello, Dark Mode!
</p>
</div>

Design Tips#

1. Don’t Use Pure Black#

/* Too harsh */
--bg-dark: #000000;
/* Easier on eyes */
--bg-dark: #0a0a0a;
--bg-dark: #121212;

2. Reduce Contrast#

/* Light mode */
--text: #000000;
/* Dark mode - slightly muted */
--text: #e5e5e5; /* Not pure white */

3. Adjust Shadows#

.card {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}
[data-theme="dark"] .card {
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
}

4. Desaturate Colors#

:root {
--accent: #3b82f6; /* Vibrant blue */
}
[data-theme="dark"] {
--accent: #60a5fa; /* Lighter, less saturated */
}

Prevent Flash#

<script>
(function() {
const theme = localStorage.getItem('theme') ||
(window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
document.documentElement.setAttribute('data-theme', theme);
})();
</script>

Put this in <head> before CSS loads!


Good dark mode = Happy eyes

Dark Mode Implementation Guide
https://blog.lukkid.dev/posts/dark-mode-guide/
Author
LUKKID
Published at
2024-06-05
License
CC BY-NC-SA 4.0