From harness-claude
Implements dark mode in Tailwind apps using CSS variables, dark class variant, system preference detection via matchMedia, localStorage persistence, and React hook. Prevents flash of wrong theme.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Implement dark mode with Tailwind's dark variant, CSS custom properties, and user preference detection
Provides Tailwind CSS patterns for responsive design and dark mode in 2025/2026, including mobile-first breakpoints, custom themes, grids, and typography scaling.
Sets up Tailwind v4 + shadcn/ui theming in React/Vite projects: installs deps, configures CSS variables with @theme inline, adds dark mode support, verifies. Fixes v4 colors, animations, @apply, migration issues.
Builds production-ready Tailwind CSS design systems including design tokens, component variants, responsive patterns, and accessibility. Useful for component libraries, theming, and UI standardization.
Share bugs, ideas, or general feedback.
Implement dark mode with Tailwind's dark variant, CSS custom properties, and user preference detection
class (manual toggle via .dark class on <html>) or media (follows OS preference). Use class for manual control.dark: prefix for overrides.dark: classes — it scales better with many components.window.matchMedia('(prefers-color-scheme: dark)'). Store their choice in localStorage.// tailwind.config.ts
const config: Config = {
darkMode: 'class', // Enable class-based dark mode
// ...
};
/* styles/globals.css */
@layer base {
:root {
--background: 255 255 255;
--foreground: 17 24 39;
--card: 249 250 251;
--primary: 59 130 246;
--muted: 107 114 128;
--border: 229 231 235;
}
.dark {
--background: 15 23 42;
--foreground: 248 250 252;
--card: 30 41 59;
--primary: 96 165 250;
--muted: 148 163 184;
--border: 51 65 85;
}
}
// hooks/use-theme.ts
import { useEffect, useState } from 'react';
type Theme = 'light' | 'dark' | 'system';
export function useTheme() {
const [theme, setThemeState] = useState<Theme>(() => {
if (typeof window === 'undefined') return 'system';
return (localStorage.getItem('theme') as Theme) ?? 'system';
});
useEffect(() => {
const root = document.documentElement;
function applyTheme(t: Theme) {
if (t === 'system') {
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
root.classList.toggle('dark', isDark);
} else {
root.classList.toggle('dark', t === 'dark');
}
}
applyTheme(theme);
// Listen for OS preference changes
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
const handler = () => {
if (theme === 'system') applyTheme('system');
};
mediaQuery.addEventListener('change', handler);
return () => mediaQuery.removeEventListener('change', handler);
}, [theme]);
const setTheme = (t: Theme) => {
setThemeState(t);
localStorage.setItem('theme', t);
};
return { theme, setTheme };
}
// Prevent flash of wrong theme — add to <head> in your HTML/layout
<script
dangerouslySetInnerHTML={{
__html: `
(function() {
var theme = localStorage.getItem('theme');
if (theme === 'dark' || (!theme && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
document.documentElement.classList.add('dark');
}
})();
`,
}}
/>
CSS variable approach vs dark: prefix:
// Per-element dark: classes (verbose, repetitive)
<div className="bg-white dark:bg-slate-800 text-gray-900 dark:text-gray-100 border-gray-200 dark:border-gray-700">
// CSS variable approach (clean, DRY)
<div className="bg-background text-foreground border-border">
// Colors switch automatically via CSS variables
Approach comparison:
dark: prefix: Simple, no CSS variables needed. Gets verbose with many elements.dark: for one-off overrides.Next.js with next-themes:
import { ThemeProvider } from 'next-themes';
function App({ children }) {
return (
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
{children}
</ThemeProvider>
);
}
Images and dark mode: Provide dark-mode variants for images, or use CSS filters:
<img className="dark:invert dark:brightness-90" src="/logo.svg" alt="Logo" />
// Or use next/image with dark mode source
Testing dark mode: In browser DevTools, toggle the dark class on <html>. Or use DevTools > Rendering > Emulate CSS media feature prefers-color-scheme: dark.
https://tailwindcss.com/docs/dark-mode