Implementing Dark Mode in React Applications
Learn how to build a dark mode toggle that persists user preferences and handles system preference detection seamlessly in your React apps.
Master the fundamentals of design tokens to create scalable, consistent, and flexible theme systems for your brand.
Design tokens are the DNA of your theme system. They're the single source of truth that bridges design and development, ensuring consistency across every color, spacing, and interaction. Without tokens, you're building themes on sand — inconsistent, fragile, and impossible to scale.
Here's the real challenge: you've got a design system in Figma, a different one in your CSS, and they're slowly drifting apart. Teams are making one-off changes. Colors don't match. Spacing feels random. And when you need to switch themes or add dark mode? It's a nightmare.
But it doesn't have to be this way. A proper token architecture transforms how you build and maintain themes. Let's explore how.
A design token is a named variable that holds a design decision. Not a color hex code — a decision. When you define `--color-primary: #10b981`, you're not just storing a color. You're saying "this is what primary means in our system."
Think of it this way: if you hardcode `#10b981` in 47 places across your codebase, changing that color becomes a treasure hunt. But if you reference `--color-primary` everywhere? You change one token, and your entire theme updates. It's the difference between updating a spreadsheet and manually editing 47 documents.
Tokens exist at multiple levels. Base tokens are the raw values — your core color palette, typography scales, spacing increments. Then you've got semantic tokens that layer meaning on top. `--color-success` is a semantic token that might reference a base token like `--color-emerald-500`. This separation matters because it lets you swap implementations without breaking your component code.
Your token system needs structure, or it becomes chaos. We're talking three distinct layers that build on each other.
Base tokens are your foundation. These are the raw materials: all your colors (emerald-50 through emerald-950), your type scale (12px, 14px, 16px, 18px, etc.), spacing increments (4px, 8px, 16px, 32px), border radiuses, and shadows. You don't use these directly in components — they're your palette.
Semantic tokens add meaning. `--color-primary`, `--color-success`, `--color-error`, `--color-text-muted`. These reference base tokens but describe intent. When you build a button component, you use semantic tokens because buttons need to communicate "this is the primary action" or "this is disabled." The semantic layer is where theming gets interesting — you can swap which base color represents "primary" without touching your component code.
Component tokens are optional but powerful. `--button-primary-background`, `--button-primary-border`, `--button-primary-hover-background`. These are pre-computed combinations that ensure consistency within specific components. They live in your component layer, not your global design system.
CSS custom properties are your best friend here. They're native to the browser, they're powerful, and they're already everywhere. When you define `--color-primary: #10b981` in your `:root`, every element can access it instantly. No build step required. No magic.
Here's how a real token system looks. You've got your base tokens sitting in a design tokens file — maybe JSON, maybe YAML, maybe just a CSS file. Tools like Figma tokens, Style Dictionary, or Token Studio let you export tokens directly from your design tool. This is crucial. It's not about developers hand-typing token names — it's about a single source feeding both design and code.
For dark mode specifically, you're leveraging the same tokens with different values. Your light theme sets `--color-bg-primary: #ffffff` and `--color-text-primary: #0f172a`. Your dark theme flips it: `--color-bg-primary: #022c22` and `--color-text-primary: #ffffff`. The component code doesn't change — it just references the tokens. That's the whole point.
Most teams implement this by creating a separate CSS file for each theme. Light theme gets `tokens-light.css`, dark theme gets `tokens-dark.css`. Then you use a data attribute or class selector to switch which one applies. Some approaches use JavaScript to swap tokens dynamically, others use media queries to detect system preferences. All valid — it depends on your use case.
Open-source tool from Amazon. You define tokens in JSON, and it generates CSS, JavaScript, iOS, Android, and more. Perfect if you need tokens across multiple platforms and want a centralized source.
Native plugin that lets designers create tokens in Figma and export them directly. The bridge between design and development. If your team uses Figma, this closes the gap completely.
Multi-platform token management. Works with Figma, Adobe XD, and generates exports for web, mobile, and design systems. More advanced workflow if you need complex token hierarchies.
CSS-in-JS solution with tokens built in. You define your design tokens, and Panda generates typed utilities and components. Great for teams building design systems with React or Vue.
Not strictly a token tool, but Tailwind's configuration system works like tokens. You define your palette, spacing, and typography once in `tailwind.config.js`, and it generates utilities automatically.
Storybook documents your components with tokens applied. Chromatic lets you manage design changes across your entire component library and catch visual regressions automatically.
Tokens aren't just about dark mode. They're about building systems that scale. When you've got 200 components and you need to rebrand? Change your tokens, and everything updates. Need to launch in a new market with different brand colors? Create a new token set, apply it, done. Accessibility requirements change and you need better contrast? Adjust your token values, not your code.
The teams we've seen do this best treat tokens like their actual design system — because that's what they are. They're documented, versioned, reviewed, and treated with the same care as code. Designers and developers aren't guessing at colors anymore. Everything's intentional.
Start small if you need to. You don't have to implement perfect semantic tokens on day one. Begin with base tokens, get them working across your codebase, then layer in semantic tokens as you go. The important part is creating that single source of truth. Everything else builds from there.
Author
Editorial Team
Written by the Chromatic Studios Editorial Team, focused on practical, tested guidance for theme switching and dark mode implementation.
Learn how to build a dark mode toggle that persists user preferences and handles system preference detection seamlessly in your React apps.
Discover how CSS custom properties make managing multiple themes simple and maintainable across your entire stylesheet.
Ensure your theme switcher meets accessibility standards while providing excellent contrast and readability across all color schemes.
This article provides educational information about design tokens and theme architecture. The approaches and tools discussed reflect current industry practices and are intended to inform decision-making. Implementation details may vary based on your specific project requirements, team expertise, and technology stack. We recommend evaluating tools and approaches within your own context before adoption. Chromatic Studios provides this content for informational purposes to support better understanding of design systems and theme implementation.