Semantic Icons

Writing

Make an SVG icon follow your text colour with currentColor

3 min read svgcssdark mode

How do you make an SVG icon match the surrounding text colour?

Set stroke or fill to currentColor. The SVG then inherits the CSS colour of its parent, so the icon changes with the text around it. This removes the need for light and dark variants, for colour props, and for an inline fill on every use.

An icon set that ships colours is an icon set you will fight. Every use needs an override, every theme needs a variant, and every variant drifts.

The fix is one keyword.

<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
  <path d="M4 20 L12 4 L20 20" />
</svg>

currentColor resolves to the computed CSS color of the element. Put the icon inside a button, and it takes the button's text colour. Change the theme, and it changes with it. No prop, no variant, no override.

What it removes

Without currentColorWith currentColor
A light and a dark version of every iconOne version
A color prop on the icon componentNone
An inline fill at every useNone
A CSS rule per contextOne rule on the parent

For a 3000 icon set the first row alone is the difference between 3000 files and 6000.

The rule that makes it work

currentColor only helps if nothing else in the file sets a colour. That means the icon file must hold shapes only, with no fill, stroke, style or class attributes of its own.

Our library stores each icon as its inner elements, and the renderer supplies the wrapper:

<!-- stored -->
<rect x="2.5" y="2.5" width="19" height="19" rx="3.5"/>
<path d="M7 15.5 L11 8.5 L15 15.5"/>

The consequence is that a change to the contract is one edit. When we needed round joins across the whole set, it was one attribute in one renderer, not 3000 file edits.

The three places it breaks

A hard coded fill in the source

Icons exported from a drawing tool almost always carry fill="#000000" on every path. That wins over the parent colour, so the icon stays black in dark mode. Strip fills and strokes at import time, not by hand later.

A multi colour icon

A flag, a logo or a colour coded status icon has colours that are part of its meaning. currentColor cannot express that. Keep those out of the monochrome set, and let them carry their own colours. Do not compromise the whole set for a handful of files.

If you need one accent inside an otherwise monochrome icon, a CSS custom property with a fallback works:

<path stroke="currentColor" d="..."/>
<circle fill="var(--icon-accent, currentColor)" cx="18" cy="6" r="3"/>

An <img> tag or a CSS background

An SVG loaded through <img src="icon.svg"> or background-image is a separate document. It has no access to your page's CSS, so currentColor resolves to black.

This is the most common surprise. If you need currentColor, the SVG must be inline in the DOM: rendered by a component, or injected. A sprite referenced with <use> keeps it, because the sprite is in the same document.

DeliverycurrentColor works
Inline <svg> in the markupYes
<use href="#id"> from an inline spriteYes
<img src="icon.svg">No
CSS background-imageNo
mask-image with background-colorEffectively, yes

That last row is the workaround for CSS-only cases. Use the SVG as a mask and let the background colour show through.

Dark mode, in one line

With currentColor, dark mode is whatever your text colour already does:

:root { color: #13161b; }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { color: #e8eaee; }
}

The icons follow. There is nothing else to do, and no second set to keep in step. See designing icons for dark mode for the cases where that is not quite enough.

Questions people ask

Does currentColor work in every browser?

Yes. It is part of SVG 1.1 and CSS Color 3, and it works everywhere including older browsers. It is one of the safest features in the platform.

Can I use currentColor for fill and stroke together?

Yes. Set both if the icon mixes filled and stroked shapes. They resolve to the same colour, which is usually what a monochrome icon wants.

How do I make one icon a different colour?

Set color on the icon or its parent, not fill. Because the icon reads currentColor, setting color: red on the wrapper turns the icon red without touching the SVG.

What about opacity for a secondary detail?

Use stroke-opacity or fill-opacity rather than a lighter colour. Opacity keeps the icon correct on any background; a hard coded lighter grey does not.

Search 3006 icons with a sentence

Ask for an icon the way you would say it.

Try the search