
The Inline SVG Trap
Your icon library might be the hidden reason your Lighthouse score is tanking—here is why componentizing every path is a recipe for DOM bloat.
The Inline SVG Trap
Your "Icon.jsx" file is probably a crime scene. I know it feels right to have a tidy library of React or Vue components for every single icon in your design system, but you’re likely paying a massive performance tax that Lighthouse is just waiting to collect.
Inlining every SVG path directly into your component tree is the quickest way to create a "DOM soup" that chokes the browser's main thread. While it seems like the "modern" way to handle assets, we’ve collectively traded performance for developer ergonomics, and the cost is higher than you think.
The math of a heavy DOM
Every time you inline an SVG, you aren't just adding an image; you’re adding a dozen or more DOM nodes. If you have a dashboard with a sidebar, a data table, and a few dropdowns, you might easily have 50 icons on screen.
Let's look at a standard "User" icon:
// The "convenient" way that scales poorly
const UserIcon = () => (
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
<circle cx="12" cy="7" r="4" />
</svg>
);On its own? Harmless. But if you render a list of 100 users, you’ve just injected 300 extra DOM nodes. The browser has to track these, calculate styles for them, and repaint them. Multiply this across an entire application, and your Total Blocking Time (TBT) starts to climb because the browser is too busy parsing a massive HTML string instead of becoming interactive.
The Caching Nightmare
When an SVG is a standalone file (like icon.svg), the browser is incredibly smart about it. It downloads it once, caches it, and forgets about it.
When you bake that SVG into a JavaScript component, you are:
1. Bloating your JS bundle: You're sending drawing instructions over the wire as text inside your .js files.
2. Forcing a re-parse: Every time that component re-renders or the JS bundle is updated, the browser has to re-process those strings.
3. Bypassing the asset cache: If you change a line of logic in your Button.jsx, the user has to re-download the SVG paths bundled inside it, even if the icons themselves haven't changed in months.
A better way: The Sprite Sheet
Remember the <img> tag? It was actually pretty good at its job. But if you need to change icon colors dynamically, the "SVG Sprite" is the middle ground that preserves performance without sacrificing control.
Instead of inlining the paths, you define them once at the top of your body (or in a separate hidden file) and reference them using the <use> tag.
Step 1: The Sprite Definition
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol id="icon-user" viewBox="0 0 24 24">
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" />
<circle cx="12" cy="7" r="4" />
</symbol>
</svg>Step 2: The Component
const Icon = ({ name, color = 'currentColor' }) => (
<svg style={{ color }}>
<use href={`#icon-${name}`} />
</svg>
);Now, no matter how many times you render the user icon, the DOM only contains a single <use> node pointing to a definition. The browser handles the heavy lifting, and your DOM stays lean.
"But I need to animate my paths!"
This is the classic "gotcha." If you’re doing complex path morphing with a library like Framer Motion or GSAP, yes—you probably need the paths in the DOM.
The rule of thumb: If it’s a static UI icon (chevron, search, user, settings), use a sprite or a standard <img> tag. If the icon needs to transform into a "close" button or do a little dance when clicked, keep it as a component.
Don't punish your entire app's performance for the 2% of icons that actually need to be "smart."
Handling Dynamic Colors
One reason developers love inlined SVGs is the ability to pass a fill or stroke prop. You can still do this with sprites! By using currentColor in your sprite definition, the SVG will inherit the text color of its parent.
/* In your CSS */
.icon-active {
color: #3b82f6; /* The SVG <use> will now be blue */
}Summary for the Performance-Minded
If your Lighthouse report is yelling at you about "Excessive DOM Size," look at your icons first.
- Stop componentizing every single .svg into a massive icons/ folder.
- Start using SVG sprites for static UI elements.
- Use tools like svgo to strip out the junk (metadata, comments, and hidden paths) that design tools like Illustrator or Figma leave behind.
Your users don't care how clean your Icon.jsx file looks—they care that the page loads fast enough to actually use. Stay lean.

