Skip to main content

How to change color in svg file?

SVG color is controlled through fill (interior of a shape) and stroke (outline). Both can be set in the markup, through CSS, or with JavaScript - but which method actually works depends on how the SVG is loaded into the page.

Theory

TL;DR

  • fill paints the inside of a shape, stroke paints its border
  • CSS works on SVG only when the SVG is inline in the HTML document
  • External SVGs loaded via <img> are browser-sandboxed - no CSS gets in
  • currentColor makes a shape inherit the color value from its nearest ancestor
  • Decision rule: inline SVG + CSS for theming; <img> for isolation; <object> for partial control

Quick example

html
<!-- Direct attribute - works everywhere --> <circle fill="red" stroke="blue" stroke-width="2" /> <!-- CSS on inline SVG - only when SVG is inside HTML --> <style> circle { fill: green; } </style> <svg><circle r="40" cx="50" cy="50" /></svg> <!-- currentColor - icon follows parent text color --> <div style="color: navy;"> <svg width="24" height="24" viewBox="0 0 24 24"> <path fill="currentColor" d="M12 2L15 10H23L17 15L19 23L12 18L5 23L7 15L1 10H9L12 2Z" /> </svg> </div> <!-- Star renders in navy -->

Inline SVG elements are DOM nodes. The browser reads fill and stroke from either the element's attributes or its computed CSS style, then passes the result to the graphics renderer. For SVGs loaded via <img>, none of that applies.

The external SVG boundary

When you load an SVG with <img src="icon.svg">, the browser treats it as an opaque image. The SVG's internal DOM is not part of the parent document. CSS selectors from the page never reach inside. This is a browser security boundary, not something you can override with more specific selectors.

When you need dynamic colors on an external SVG, the options are:

  • Embed it inline with <svg> directly in the HTML
  • Use <object data="icon.svg"> (CSS filters apply to the <object> container, not the SVG internals)
  • Use <use> referencing an inline <symbol> definition

When to use each method

  • Direct fill/stroke attributes for static colors or when you control the SVG source file
  • CSS on inline SVG for hover states, theming, dark mode, and responsive color changes
  • currentColor for icon systems where icons should match surrounding text color
  • JavaScript for real-time color changes driven by user interaction or data values

Common mistakes

Mistake 1: Styling an SVG loaded via <img> with CSS

html
<style> svg circle { fill: red; } </style> <img src="chart.svg" /> <!-- Circle stays its original color. The rule never reaches it. -->

The browser does not parse the SVG's internal structure when it is loaded as an image. Fix: embed the SVG inline, or use <object>.

Mistake 2: CSS losing to the fill attribute

html
<style> circle { fill: blue; } </style> <svg> <circle fill="red" cx="50" cy="50" r="40" /> <!-- Renders RED. The attribute wins. --> </svg>

SVG attributes act like inline styles and have higher specificity than external or embedded CSS rules. This is the first thing to check when a color change does nothing. Either remove the fill attribute from the SVG source or add !important: circle { fill: blue !important; }.

Mistake 3: Setting color instead of fill

html
<style> svg { color: red; } </style> <svg><circle cx="50" cy="50" r="40" /></svg> <!-- Circle is not red -->

color affects text nodes, not SVG shapes. Use fill: red directly. The only time color influences an SVG shape is when that shape has fill="currentColor".

Mistake 4: Unexpected currentColor scope

html
<div style="color: blue;"> <svg> <circle fill="currentColor" cx="30" cy="50" r="20" /> <g style="color: red;"> <rect fill="currentColor" x="60" y="30" width="40" height="40" /> <!-- rect is RED, circle is BLUE --> </g> </svg> </div>

currentColor resolves to the color value of the nearest ancestor. This is useful for scoped theming, but it catches people off guard the first time.

Real-world usage

  • Heroicons, Feather Icons - all icons ship with fill="currentColor" so they automatically adapt to button, link, and header colors
  • D3.js, Recharts - fill and stroke are set dynamically on SVG elements based on data values
  • Styled-components, Emotion - theme variables flow into inline SVGs through CSS custom properties
  • GSAP, Framer Motion - animate fill and stroke for morphing and color transition effects

Follow-up questions

Q: Why doesn't CSS work on SVG loaded via <img>?
A: The browser sandboxes external images. The SVG's DOM is not accessible to the parent document, so no selectors, no variables, and no scripts can reach it. This is enforced at the browser level for security.

Q: Can I use CSS custom properties inside SVG?
A: Yes, if the SVG is inline. <circle fill="var(--brand-color)" /> works and is a clean way to theme an icon system from a single CSS variable. External SVGs cannot access variables from the parent page.

Q: How do I change SVG color on hover?
A: Use CSS pseudo-classes on inline SVG: svg path:hover { fill: #2563eb; }. For an external SVG via <img>, the practical options are a CSS filter on the <img> element or swapping the src with JavaScript on the mouseenter event.

Q: (Senior) How would you build a dark mode system for 50 SVG icons without duplicating markup?
A: Embed all icons inline with fill="currentColor". Set color on a wrapper via a CSS custom property: .icon { color: var(--icon-color); }. Define the variable per mode: @media (prefers-color-scheme: dark) { :root { --icon-color: white; } }. Every icon updates automatically with zero markup changes and no JavaScript.

Examples

Static SVG with direct attributes

html
<svg width="100" height="100" viewBox="0 0 100 100"> <circle cx="50" cy="50" r="40" fill="#3b82f6" stroke="#1e40af" stroke-width="4" /> </svg> <!-- Blue circle with a darker blue border -->

Direct attributes are processed before CSS. Use them for standalone SVG files or any shape whose color should never change based on context.

Interactive icon button with currentColor

html
<style> .icon-btn { color: #6b7280; background: none; border: none; cursor: pointer; display: inline-flex; align-items: center; gap: 6px; } .icon-btn:hover { color: #2563eb; } .icon-btn svg { stroke: currentColor; width: 20px; height: 20px; } </style> <button class="icon-btn"> <svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round"> <circle cx="11" cy="11" r="6" /> <line x1="21" y1="21" x2="16.65" y2="16.65" /> </svg> Search </button> <!-- Icon is gray by default. On hover: both the text and icon turn blue. One CSS rule (color) controls both. -->

Setting stroke: currentColor (or fill: currentColor) on the <svg> ties icon color to the button's text color. Hover, focus, and disabled states all work from a single CSS property on the button, with no changes to the SVG markup.

Short Answer

Interview ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?

How to change color in svg file? | ITLead