Duotone Icons in Light and Dark Themes

How to make duotone SVG icons theme-safe with CSS variables, contrast checks, and state-token structure.

Amit Yadav
Amit Yadav

Duotone icons often look good in one theme and weak in another. The fix is not random color tweaks. You need a tokenized approach tied to theme states.

Why theme failures happen

Most issues come from one of these:

  • primary and secondary tones too close in dark mode
  • secondary opacity too low on low-contrast surfaces
  • hover/active states changing only one layer

The result is muddy icon depth or unreadable state transitions.

Start with theme tokens

:root {
  --icon-primary: #1d4ed8;
  --icon-secondary: #93c5fd;
  --icon-secondary-opacity: 0.45;
}

[data-theme="dark"] {
  --icon-primary: #93c5fd;
  --icon-secondary: #1e3a8a;
  --icon-secondary-opacity: 0.6;
}

This keeps your icon model consistent while adapting tone relationships per theme.

State model for duotone icons

Define states explicitly:

  • default
  • hover
  • active
  • disabled

For each state, decide whether both layers change or only one layer changes. In most systems:

  • hover: change primary tone
  • active: adjust primary + opacity
  • disabled: reduce both via shared opacity token

Contrast checks that matter

WCAG contrast guidance applies to meaningful interface elements, and low-contrast icons can hurt recognizability.1

Practical checks:

  1. test icon on real component backgrounds
  2. test at small sizes (16px, 20px)
  3. test disabled state visibility
  4. ensure semantic differences remain obvious

Implementation tips

  • Keep layer structure consistent across icon set
  • Use design tokens, not hardcoded per-icon values
  • Document allowed opacity range for second layer
  • Add screenshot regression tests for theme variants
Design-system rule

Treat duotone as a component contract. If each feature team picks random two-tone values, consistency will collapse quickly.

Practical FAQ

Not always, but dark surfaces often need stronger separation between layers. Test with real component backgrounds.

That is valid as long as semantic meaning and hierarchy stay consistent.

Use shared disabled tokens that reduce both layer prominence together.

Theme QA checklist

  1. test default/hover/active/disabled
  2. test icon contrast on cards and panels
  3. verify legibility at 16px and 20px

Final recommendation

Document duotone tokens and state behavior in your design system before wide rollout. Without this contract, theme quality drops quickly across teams.

Regression testing tip

Capture visual snapshots of key duotone components in both themes. Theme drift usually appears first in secondary-tone contrast and disabled states.

Final note

Theme-safe duotone depends on token discipline and visual testing, not ad-hoc color tweaks per component.

A documented token contract is the fastest way to preserve quality across releases.

Additional source references: 2 3.

Sources

Footnotes

  1. WCAG: Contrast Minimum Understanding

  2. MDN: CSS custom properties

  3. MDN: SVG opacity

Share this post