Make an SVG icon follow your text colour with currentColor
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 currentColor | With currentColor |
|---|---|
| A light and a dark version of every icon | One version |
A color prop on the icon component | None |
An inline fill at every use | None |
| A CSS rule per context | One 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.
| Delivery | currentColor works |
|---|---|
Inline <svg> in the markup | Yes |
<use href="#id"> from an inline sprite | Yes |
<img src="icon.svg"> | No |
CSS background-image | No |
mask-image with background-color | Effectively, 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.