SVG fill="currentColor": Change Icon Color with CSS
fill="currentColor" makes an inline SVG use the CSS color of its parent. How it works per MDN, fill vs stroke, hover and dark mode, and why it fails with img.
On this page
To change an SVG icon's color with CSS, set fill="currentColor" (or stroke="currentColor" for outline icons) inside the SVG, then set color on the icon or any parent. The icon follows the text color, so hover states, themes and dark mode need no extra icon rules.
Quick answer
- currentColor is the value of the element's CSS color property, so fill=currentColor paints the icon in the text color.
- Filled icons use fill=currentColor. Outline icons use fill=none and stroke=currentColor.
- A hardcoded fill attribute can be overridden from CSS, because presentation attributes have a specificity of 0.
- It does not work with img or background-image. CSS cannot reach inside an external SVG file. Inline the SVG, or use a CSS mask.
How currentColor works
MDN's definition: "The currentColor keyword represents the value of an element's color property. This lets you use the color value on properties that do not receive it by default." (MDN, <color> value).
fill and stroke do not take the text color by default. currentColor connects them to it. Because color is inherited, setting it on a button colors every icon inside:
<button class="icon-btn" aria-label="Search">
<svg viewBox="0 0 24 24" width="20" height="20"
fill="none" stroke="currentColor" stroke-width="2">
<circle cx="11" cy="11" r="8" />
<path d="m21 21-4.3-4.3" />
</svg>
</button>.icon-btn { color: #334155; }
.icon-btn:hover,
.icon-btn:focus-visible { color: #2563eb; }One rule changes both the label text and the icon.
fill vs stroke
| Icon style | SVG attributes | Example packs |
|---|---|---|
| Filled (solid shapes) | fill="currentColor" | Material Design Icons, Font Awesome Solid |
| Outline (lines) | fill="none" stroke="currentColor" | Lucide, Tabler |
| Mixed (outline plus filled dots) | stroke="currentColor" on lines, fill="currentColor" on the filled parts | Some duotone and two-tone sets |
If an outline icon turns into a solid blob, it has fill="currentColor" where it needs fill="none". If a filled icon goes invisible, it has fill="none".
Icons you copy from All SVG Icons already use currentColor, so they follow your text color out of the box.
Override a hardcoded color
Many exported SVGs carry fill="#000" on each path. You do not have to edit the file. Per MDN, presentation attributes like fill and stroke "set CSS property values on an element with a specificity of 0, so other author styles in a stylesheet or style attribute can override them":
.icon path,
.icon circle,
.icon rect {
fill: currentColor;
}This does not beat an inline style="fill:#000" on the path, because inline styles win over stylesheet rules. For those files, remove the inline style, or recolor the file once in the SVG Color Editor.
Hover, focus and dark mode
Keep icon colors in custom properties, so a theme change is one swap:
:root {
--icon: #475569;
--icon-hover: #1d4ed8;
}
@media (prefers-color-scheme: dark) {
:root {
--icon: #cbd5e1;
--icon-hover: #93c5fd;
}
}
.icon-btn { color: var(--icon); }
.icon-btn:hover { color: var(--icon-hover); }Check contrast for both themes. WCAG 2.2 asks for 3:1 against the background for icons that carry meaning (WCAG 2.2, non-text contrast).
Tailwind and React
In Tailwind, text-* classes set color, so they color any currentColor icon:
<button class="text-zinc-600 hover:text-emerald-600">
<svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor">...</svg>
</button>React icon libraries such as lucide-react default their color prop to currentColor, so a parent class is enough:
import { Bell } from 'lucide-react';
<button className="text-slate-600 hover:text-blue-600" aria-label="Notifications">
<Bell size={20} />
</button>More patterns, including dark mode variants, are in our Tailwind SVG icons guide.
Why currentColor is not working
- The SVG is loaded with
<img>orbackground-image. It renders as a separate document, so page CSS cannot change its fill. Inline the SVG or use the mask method below. - Paths have their own hardcoded
fill.currentColoron the<svg>element does nothing if each<path>setsfill="#000". Use the override rule above. - An inline
styleattribute on a path sets the color. Remove it. coloris set on the wrong element. Inspect the<svg>in DevTools, Computed tab, and check the value ofcolor.- Fill and stroke are swapped for the icon style. See the table above.
Color an SVG used as img or background
When you cannot inline the file, use it as a CSS mask and paint the box with currentColor. The SVG's shape cuts out the color:
.icon-mask {
display: inline-block;
width: 1.25rem;
height: 1.25rem;
background-color: currentColor;
mask: url('/icons/bell.svg') no-repeat center / contain;
}The icon now follows color like inline SVG, at the cost of a single color only. See MDN, mask for the shorthand.
Icons to test with
These outline icons all use stroke="currentColor". Copy one into your page and change the parent color:
FAQ
What does fill=currentColor do in SVG?
Should I use fill or stroke with currentColor?
Can CSS override a fill attribute in an SVG?
Why can't I change the color of an SVG in an img tag?
How do I change an SVG color on hover?
Related posts