Skip to main content
stackloader
  • Home
  • Services
  • Portfolio
  • Technologies
  • About
Get started
stackloader
  • Home
  • Services
  • Portfolio
  • Technologies
  • About
Get started
stackloader

AI-Driven Code, Human-Centric Impact.

Product

  • Features
  • Integrations

Company

  • About
  • Blog
  • Careers
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 stackloader, Inc. All rights reserved.

Built with precision.

We use cookies

To improve your experience. Cookie policy

  1. stackloader
  2. Blog
  3. Designing for Dark Mode from Day One

Design

Designing for Dark Mode from Day One

Dark mode is easier to add at the start than to retrofit — and the decisions you make in your token system determine whether it feels considered or patchy.

Léa Fontaine

Léa Fontaine

Design Lead

September 5, 20246 min read

Dark mode is the single most-requested feature in modern application design. It's also the feature most commonly implemented as an afterthought — a filter: invert() hack or a handful of hard-coded overrides that make the dark version feel like a different product entirely.

Done well, dark mode reveals the quality of your design token system. Done poorly, it exposes the lack of one.

Start with semantic tokens, not raw colours

The mistake is mapping utilities directly to palette values: bg-zinc-900 dark:bg-zinc-50. The moment you do this, every new dark mode component is a hunt-and-replace problem.

The right model: define semantic tokens as CSS custom properties, map your Tailwind utilities to those tokens, and change the tokens per theme. With Tailwind v4's @theme inline and CSS variable system:

:root { --bg-base: #ffffff; --text-primary: #09090b; }
.dark { --bg-base: #0a0a0a; --text-primary: #fafafa; }
@theme inline { --color-bg-base: var(--bg-base); }

Now bg-bg-base works in both themes without any dark: prefix. Your components stay clean.

The palette construction problem

Light mode colours don't invert cleanly. A zinc-900 on white reads at contrast ratio 19:1 — dramatically over-engineered for body copy. In dark mode, zinc-50 on zinc-950 is also fine, but the relationship between foreground and background saturations needs manual tuning to feel right.

A practical approach: build your dark palette independently, targeting WCAG AA (4.5:1 for body text, 3:1 for large text and UI components) rather than copying inverted light-mode values.

The accent colour trap

Your brand accent (say, #7C5CFF) might pass contrast on white but fail on your dark background. Always test both. A common fix is a slightly lighter accent for dark mode — #8F72FF maintains the hue but gains enough brightness to hit 4.5:1 against a near-black surface.

Respect the system preference

prefers-color-scheme is a user's statement about their environment, accessibility needs, or personal preference. Default to it. Offer an override in settings. Persist the override to localStorage. This is the pattern every mature product has settled on — and it's what we implement in every project.

Share
Léa Fontaine

Written by

Léa Fontaine

Design Lead

Léa leads product design at stackloader, with a focus on design systems, accessibility, and the intersection of engineering and user experience. She believes good design is invisible — and dark mode is a test of whether your token architecture is real or decorative.

In this article

  1. Start with semantic tokens, not raw colours
  2. The palette construction problem
  3. The accent colour trap
  4. Respect the system preference

More from the blog

The Practical Case for JSDoc Over TypeScript in 2025

Engineering

The Practical Case for JSDoc Over TypeScript in 2025

Jan 14, 2025·7 min
What We Learned Shipping RAG to Production at Scale

AI & ML

What We Learned Shipping RAG to Production at Scale

Dec 12, 2024·11 min
Zero-Downtime Deployments on AWS: A Practical Playbook

DevOps

Zero-Downtime Deployments on AWS: A Practical Playbook

Nov 28, 2024·9 min

Newsletter

Stay ahead of the build

New articles on AI, DevOps, and engineering craft. Roughly twice a month. No noise, no promotions — just the good stuff.