How taste-skill Enforces Dark Mode by Default with Dual-Theme Support
taste-skill enforces dark mode by default through a three-layer architecture that locks the entire page to a single theme, mandates dual-theme support for every component, and provides a strict protocol for implementing Tailwind or CSS-variable-based theming.
The taste-skill design system treats dark mode as a first-class constraint rather than an optional feature. Defined in skills/taste-skill/SKILL.md, the specification requires every consumer-facing page to support both light and dark appearances while strictly preventing mid-page theme switches. This approach ensures brand consistency, accessibility, and predictable visual hierarchy across the entire user interface.
The Three-Layer Dark Mode Architecture
According to the taste-skill source code, dark mode enforcement operates through three architectural layers codified in SKILL.md:
Page-Level Theme Lock (Lines 341–349)
The Page Theme Lock guarantees that an entire page uses exactly one theme—light, dark, or auto—and explicitly forbids mid-page theme transitions. The system detects the user's preference via prefers-color-scheme, locks that choice for the duration of the session, and prohibits any child component from overriding it. This rule prevents jarring visual shifts when users scroll or navigate between sections.
Mandatory Dark-Mode Support (Lines 31–36)
Every consumer-facing page must be built for both light and dark modes. The specification forces designers to adopt either Tailwind’s dark: utilities or CSS custom-property theming. Components must respect the system preference unless the brand explicitly overrides it, ensuring no single-theme interfaces exist in production.
Dual-Mode Protocol (Lines 574–585)
The Dual-Mode Protocol declares the default implementation strategy and quality standards. It mandates choosing between Tailwind’s dark: variant (the default) or a CSS-variables approach, while enforcing contrast parity, visual hierarchy preservation, brand-color fidelity, and the prohibition of pure black (#000000) or pure white (#FFFFFF) values.
Implementing the Dual-Theme Strategy
taste-skill supports two mutually exclusive implementation paths, both of which must respect the single-theme lock:
Tailwind dark: Variant (Default)
The default approach uses Tailwind’s dark: modifier to pair every color utility with its dark counterpart. This requires detecting the system preference and applying the dark class to the root html element once at load time.
// layout.tsx - Theme detection and lock
"use client";
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
const theme = prefersDark ? 'dark' : 'light'; // Auto-detect and lock
Components use the dark: prefix for conditional styling without managing state:
// Hero component with Tailwind dual-theme support
export function Hero() {
return (
<header className="min-h-[100dvh] flex items-center justify-center bg-white dark:bg-zinc-950">
<h1 className="text-5xl font-bold text-gray-900 dark:text-gray-100">
Your Product
</h1>
<p className="mt-4 text-gray-600 dark:text-gray-400">
Sub-headline that works in both light and dark.
</p>
</header>
);
}
CSS-Variable Theming
For design systems like shadcn/ui or Radix Themes, taste-skill permits a semantic token approach using CSS custom properties. The variables swap values under a [data-theme="dark"] selector or media query.
/* Global theme tokens in globals.css */
:root {
--surface: #f5f5f5;
--text-primary: #111827;
}
[data-theme="dark"] {
--surface: #111827;
--text-primary: #f5f5f5;
}
JSX components reference these tokens directly, ensuring the theme change propagates from the root:
// Card component using CSS variables
export function Card() {
return (
<article className="rounded-lg p-6 bg-[var(--surface)] text-[var(--text-primary)] shadow-md">
<h2 className="text-2xl font-semibold">Feature</h2>
<p className="mt-2">Description that stays readable in light & dark.</p>
</article>
);
}
Enforcing the Single-Theme Lock
To comply with taste-skill’s Page Theme Lock, the theme must be set exactly once at the layout level and never modified by child components. The root html element receives the theme class or data attribute, and all descendants inherit this value.
// layout.tsx - Theme lock implementation
export default function Layout({ children }: { children: React.ReactNode }) {
return (
<html
lang="en"
className={theme} // "light" | "dark"
data-theme={theme} // For CSS-variable approach
>
<body>{children}</body>
</html>
);
}
Child components are strictly forbidden from re-assigning class="dark" or data-theme="dark". If a brand requires a manual toggle, the switch must affect the entire page by updating the root element, not individual sections:
const toggleTheme = () => {
const newTheme = theme === 'dark' ? 'light' : 'dark';
document.documentElement.className = newTheme;
};
Summary
- taste-skill enforces dark mode through a three-layer architecture defined in
skills/taste-skill/SKILL.md: Page Theme Lock, Mandatory Dark-Mode Support, and Dual-Mode Protocol. - The Page Theme Lock (lines 341–349) prevents mid-page theme switches by locking the entire document to a single theme determined at load time based on
prefers-color-scheme. - Developers must choose between Tailwind
dark:utilities (default) or CSS-variable theming, but cannot mix strategies within a single project. - The specification forbids pure black and white values while requiring contrast parity and brand-color fidelity across both themes.
- Theme overrides and manual toggles must operate at the root level only, ensuring no child components violate the single-theme constraint.
Frequently Asked Questions
How does taste-skill prevent mid-page theme switching?
The Page Theme Lock rule in SKILL.md (lines 341–349) explicitly forbids mid-page theme flips by requiring the theme to be set once at the root html element. Child components cannot reassign theme classes or attributes, ensuring visual consistency throughout the user session and preventing layout shifts during navigation.
What are the two approved theming strategies in taste-skill?
taste-skill supports Tailwind’s dark: variant as the default approach, where utilities are paired with dark counterparts using the class strategy, and a CSS-variables approach using semantic tokens that swap values under [data-theme="dark"]. Both methods must respect the single-theme lock and detect the system preference via prefers-color-scheme unless explicitly overridden by brand requirements.
Why does taste-skill prohibit pure black and white color values?
The Dual-Mode Protocol (lines 574–585) forbids pure black (#000000) and pure white (#FFFFFF) to maintain brand-color fidelity and reduce eye strain in dark environments. The specification requires using off-black and off-white shades (such as zinc-950 or #111827) that preserve visual hierarchy while meeting WCAG contrast accessibility standards across both themes.
Can brands override the automatic system preference detection?
Yes, brands may explicitly override the prefers-color-scheme detection to force a fixed light or dark mode, but they must still adhere to the Mandatory Dark-Mode Support rule (lines 31–36). This means the interface must be architected for both themes even if only one is displayed, and the chosen theme must remain locked at the page level without per-section variations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →