<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[SVG to React Blog]]></title><description><![CDATA[SVG to React Blog]]></description><link>https://svgtoreact.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Tue, 03 Nov 2026 06:21:42 GMT</lastBuildDate><atom:link href="https://svgtoreact.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[currentColor: the one SVG trick that makes icons themeable]]></title><description><![CDATA[Every frontend codebase eventually grows an icon problem. The designer hands over icons that are dark grey. Then the primary button needs them white, the…]]></description><link>https://svgtoreact.hashnode.dev/currentcolor-the-one-svg-trick-that-makes-icons-themeable</link><guid isPermaLink="true">https://svgtoreact.hashnode.dev/currentcolor-the-one-svg-trick-that-makes-icons-themeable</guid><category><![CDATA[SVG]]></category><category><![CDATA[CSS]]></category><category><![CDATA[React]]></category><dc:creator><![CDATA[SVG to React]]></dc:creator><pubDate>Sat, 31 Oct 2026 08:48:03 GMT</pubDate><content:encoded><![CDATA[<p>Every frontend codebase eventually grows an icon problem. The designer hands over icons that are dark grey. Then the primary button needs them white, the danger menu item needs them red, dark mode needs them light, and hover states need yet another colour. Before long you have <code>icon-close-white.svg</code>, <code>icon-close-red.svg</code> and a CSS file full of filter hacks.</p>
<p>You can avoid all of that with one CSS keyword that has been in every browser for years: <code>currentColor</code>.</p>
<h2>What currentColor means</h2>
<p><code>currentColor</code> is a CSS value that resolves to the element's computed <code>color</code> property. In ordinary HTML it's mostly a curiosity:</p>
<pre><code class="language-css">.card {
  color: #0f766e;
  border: 2px solid currentColor; /* border is teal too */
}
</code></pre>
<p>In SVG it is much more useful, because <code>fill</code> and <code>stroke</code> accept it. An icon whose paths use <code>fill="currentColor"</code> takes on the text colour of whatever it sits inside, and that colour inherits down the tree like any other text colour.</p>
<pre><code class="language-html">&lt;svg viewBox="0 0 24 24" width="24" height="24" aria-hidden="true"&gt;
  &lt;path fill="currentColor" d="M12 2l3 7h7l-5.5 4 2 7L12 16l-6.5 4 2-7L2 9h7z"/&gt;
&lt;/svg&gt;
</code></pre>
<p>Put that inside <code>&lt;a style="color: crimson"&gt;</code> and the star is crimson. Put it in a paragraph with <code>color: white</code> and the star is white. The SVG file stays the same.</p>
<h2>Converting an existing icon</h2>
<p>Most exported icons look like this:</p>
<pre><code class="language-xml">&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"&gt;
  &lt;path fill="#1F2937" d="M6 6l12 12M18 6L6 18"/&gt;
&lt;/svg&gt;
</code></pre>
<p>Or, for outline icons:</p>
<pre><code class="language-xml">&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"&gt;
  &lt;path stroke="#1F2937" stroke-width="2" d="M6 6l12 12M18 6L6 18"/&gt;
&lt;/svg&gt;
</code></pre>
<p>The fix is to replace each hard-coded colour with <code>currentColor</code> and leave <code>fill="none"</code> alone:</p>
<pre><code class="language-xml">&lt;svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"&gt;
  &lt;path stroke="currentColor" stroke-width="2" d="M6 6l12 12M18 6L6 18"/&gt;
&lt;/svg&gt;
</code></pre>
<p>A neat trick is to set the value once on the root <code>&lt;svg&gt;</code>. <code>fill</code> and <code>stroke</code> are inherited properties in SVG, so child shapes without their own value pick up the root's:</p>
<pre><code class="language-xml">&lt;svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"&gt;
  &lt;path d="M6 6l12 12M18 6L6 18"/&gt;
  &lt;circle cx="12" cy="12" r="10"/&gt;
&lt;/svg&gt;
</code></pre>
<p>This is how popular sets like Lucide and Feather are built, and it's why they theme so easily.</p>
<h2>Using it in React</h2>
<p>In a React component, the icon follows its parent's colour automatically:</p>
<pre><code class="language-jsx">function CloseIcon(props) {
  return (
    &lt;svg viewBox="0 0 24 24" width="20" height="20" fill="none"
         stroke="currentColor" strokeWidth={2} aria-hidden="true" {...props}&gt;
      &lt;path d="M6 6l12 12M18 6L6 18" /&gt;
    &lt;/svg&gt;
  );
}

export function DangerButton() {
  return (
    &lt;button style={{ color: "#b91c1c" }}&gt;
      &lt;CloseIcon /&gt; Delete
    &lt;/button&gt;
  );
}
</code></pre>
<p>With Tailwind, a colour utility on the parent or the icon itself is all it takes:</p>
<pre><code class="language-jsx">&lt;button className="text-slate-600 hover:text-teal-600"&gt;
  &lt;CloseIcon className="inline-block" /&gt;
&lt;/button&gt;
</code></pre>
<p>Hover changes the button's <code>color</code>, and the icon follows. There's no second asset and no extra CSS rule.</p>
<h2>Dark mode for free</h2>
<p>Because the colour comes from CSS, dark mode is just a variable swap:</p>
<pre><code class="language-css">:root { --text: #0f172a; }
@media (prefers-color-scheme: dark) {
  :root { --text: #e2e8f0; }
}
body { color: var(--text); }
</code></pre>
<p>Every <code>currentColor</code> icon on the page switches with the text. Compare that with maintaining a light and a dark version of every file.</p>
<h2>Where it doesn't work</h2>
<p><code>&lt;img src="icon.svg"&gt;</code> <strong>and CSS</strong> <code>background-image</code><strong>.</strong> An SVG loaded as an image is an isolated document. It can't see your page's CSS, so <code>currentColor</code> resolves to the SVG's own default colour, which is usually black. To theme an icon, it must be inline SVG (including JSX components) or referenced via <code>&lt;use&gt;</code> from an inline sprite. For background-style usage, CSS <code>mask-image</code> with <code>background-color: currentColor</code> is a workable alternative:</p>
<pre><code class="language-css">.icon-close {
  width: 1em; height: 1em;
  background-color: currentColor;
  -webkit-mask: url("/icons/close.svg") center / contain no-repeat;
          mask: url("/icons/close.svg") center / contain no-repeat;
}
</code></pre>
<p><strong>Multi-colour icons and illustrations.</strong> If an icon has two or three intentional colours, replacing them all with <code>currentColor</code> flattens it. One option is to use <code>currentColor</code> for the main shape and CSS custom properties for the accents:</p>
<pre><code class="language-xml">&lt;path fill="currentColor" d="..."/&gt;
&lt;path fill="var(--icon-accent, #14b8a6)" d="..."/&gt;
</code></pre>
<p>That only works for inline SVG too.</p>
<p><strong>Inline</strong> <code>style</code> <strong>attributes and embedded</strong> <code>&lt;style&gt;</code> <strong>blocks.</strong> Exported files sometimes carry <code>style="fill:#333"</code> or a <code>&lt;style&gt;.cls-1{fill:#333}&lt;/style&gt;</code> block. Those override presentation attributes, so replacing only <code>fill=""</code> won't change anything. Check for both.</p>
<p><strong>Opacity tricks.</strong> Some icons use a lighter shade for a secondary layer. Replace that with <code>currentColor</code> plus <code>opacity="0.4"</code>, and the shading keeps working in any colour.</p>
<h2>Overriding a single icon</h2>
<p>Sometimes one icon should break from the text colour, like a success check in green inside a grey sentence. You don't need a special variant. Set <code>color</code> on the icon itself:</p>
<pre><code class="language-jsx">&lt;p className="text-slate-600"&gt;
  Saved &lt;CheckIcon style={{ color: "#16a34a" }} /&gt; just now
&lt;/p&gt;
</code></pre>
<p><code>currentColor</code> reads the closest computed <code>color</code>, so the icon's own value wins over its parent's. The same works with a class like <code>text-green-600</code>. Keeping the colour on <code>color</code> rather than <code>fill</code> means there's still only one property to control every icon, whether it inherits or is overridden.</p>
<h2>A quick checklist</h2>
<ul>
<li>Single-colour icon? Use <code>currentColor</code> for <code>fill</code> or <code>stroke</code>, ideally on the root.</li>
<li>Keep <code>fill="none"</code> on outline icons.</li>
<li>Remove colours set in <code>style</code> attributes and <code>&lt;style&gt;</code> blocks.</li>
<li>Render inline (or as a component), not through <code>&lt;img&gt;</code>.</li>
<li>Keep <code>viewBox</code> so the icon scales with <code>width</code> and <code>height</code>, or with <code>1em</code> sizing.</li>
<li>Add <code>aria-hidden="true"</code> to decorative icons.</li>
</ul>
<p>If you're turning icons into components anyway, the <a href="https://www.svgtoreact.com/">SVG to React converter</a> can swap colours for <code>currentColor</code> during conversion, and the <a href="https://www.svgtoreact.com/guides/currentcolor/">currentColor guide</a> covers the edge cases in more detail.</p>
<p>One keyword, one colour source, and your icons follow your theme instead of fighting it.</p>
]]></content:encoded></item></channel></rss>