Duotone SVG Icons: Manage Opacity & Color with CSS

Duotone SVG icons create visual depth by dividing a single graphic into primary and secondary layers. This article explains how developers use dedicated CSS classes and custom properties to control the color, opacity, and inheritance of these distinct SVG paths. By separating the visual layers within the vector markup, you can dynamically adapt icons across themes, hover states, and design systems without altering the underlying SVG code.

SVG Structure and Layer Separation

The foundation of a duotone icon relies on separating elements into distinct SVG <path> or <g> (group) elements. Instead of hardcoding fill attributes directly inside the markup, each layer is assigned a specific class name.

<svg viewBox="0 0 24 24" class="icon-duotone">
  <path class="icon-primary" d="..." />
  <path class="icon-secondary" d="..." />
</svg>

Separating paths allows stylesheets to target individual vector components independently.

Controlling Secondary Opacity

Secondary layer transparency creates the signature duotone look. This effect is achieved in CSS using either the standard opacity property or the SVG-specific fill-opacity property on the secondary class.

.icon-duotone .icon-secondary {
  opacity: 0.4;
}

Using opacity applies transparency to the entire targeted element, including any borders, while fill-opacity isolates transparency strictly to the fill area. Using CSS variables makes this value easily adjustable across components:

.icon-duotone {
  --icon-secondary-alpha: 0.4;
}

.icon-duotone .icon-secondary {
  opacity: var(--icon-secondary-alpha);
}

Color Management via currentColor and CSS Variables

By default, duotone icons often inherit the surrounding text color using fill: currentColor. When applied to both layers, the secondary layer automatically produces a lighter tint of the primary color due to its reduced opacity:

.icon-duotone .icon-primary,
.icon-duotone .icon-secondary {
  fill: currentColor;
}

To create multi-color duotone effects, developers use CSS custom properties to assign distinct color values to each class:

.icon-duotone {
  --duotone-primary: #1e293b;
  --duotone-secondary: #3b82f6;
}

.icon-duotone .icon-primary {
  fill: var(--duotone-primary);
}

.icon-duotone .icon-secondary {
  fill: var(--duotone-secondary);
}

Handling Dynamic States and Themes

Because all visual attributes are mapped to CSS classes, interactive states such as :hover, :focus, or dark mode variations can be modified globally or locally:

/* Swapping opacity and colors on hover */
.button:hover .icon-duotone .icon-secondary {
  opacity: 0.8;
  fill: var(--duotone-primary);
}

/* Inverting emphasis in dark mode */
[data-theme="dark"] .icon-duotone {
  --duotone-primary: #f8fafc;
  --duotone-secondary: #94a3b8;
  --icon-secondary-alpha: 0.6;
}

Targeting SVG layers through CSS classes ensures high flexibility, reduces redundant markup, and keeps design logic centralized within stylesheets.