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
fillpaints the inside of a shape,strokepaints 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 currentColormakes a shape inherit thecolorvalue from its nearest ancestor- Decision rule: inline SVG + CSS for theming;
<img>for isolation;<object>for partial control
Quick example
<!-- 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/strokeattributes 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
currentColorfor 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
<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
<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
<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
<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 -
fillandstrokeare 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
fillandstrokefor 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
<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
<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 readyA concise answer to help you respond confidently on this topic during an interview.