Predictable SVG IDs with SVGO’s cleanupIDs Plugin
Learn how to use SVGO’s cleanupIDs plugin to generate scoped, deterministic IDs in SVG assets, keep file size low, and avoid clashes when inlining many icons.
18 Jul 2025, 13:19 UTC

Why SVG IDs Matter When You Inline
When you drop an SVG straight into the DOM, every <defs> element, <use> reference, or CSS selector that points to an id must be unique on the page. A single icon set that ships 200 files can create hundreds of IDs. If you inline them all, the risk of accidental collisions rises, and the resulting CSS or JavaScript that relies on those IDs can break. At the same time, developers often want the file size to stay minimal so that the icons load quickly.
Enter SVGO’s cleanupIDs Plugin
SVGO’s cleanupIDs plugin is designed to solve exactly that dilemma. It walks the SVG DOM once, renames every id to a short deterministic token (by default a, b, c, …), and rewrites every reference that points to those IDs, whether it’s a xlink:href, a url(#…) in CSS, or a document.getElementById call in JavaScript. The visual result is unchanged, but the file shrinks because the attribute values are now 1‑2 characters instead of 20‑30.
Adding a Namespace with prefixIds
When you inline dozens of icons, you can’t afford to let the short IDs collide. SVGO lets you prepend a custom prefix to every generated ID. For example, prefixIds='icon-' turns a into icon-a. Because the prefix is the same for all icons, you can still keep the IDs short while guaranteeing uniqueness across the page.
Practical Example: From Source to Inlined Icon
Below is a minimal workflow that shows the entire pipeline, from a raw SVG to an inlined, scoped icon that can be styled with CSS.
- Source SVG –
heart.svgcontains two paths with IDsheartandheart-shadow.<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <defs> <clipPath id="clip-heart"> <path d="M12 21.35L10.55 20.03C5.4 15.36 2 12.28 2 8.5c0-3.86 3.14-7 7-7s7 3.14 7 7c0 3.78-3.4 6.86-8.55 11.53L12 21.35z" /> </clipPath> </defs> <g clip-path="url(#clip-heart)"> <path id="heart" d="..." fill="red" /> <path id="heart-shadow" d="..." fill="rgba(0,0,0,0.3)" /> </g> </svg> - Run SVGO – In the terminal, execute:
svgo --enable=cleanupIDs --prefixIds='icon-' heart.svg -o heart-optimized.svgSVGO will rename
clip-hearttoicon-a,hearttoicon-b, andheart-shadowtoicon-c. All references inside the SVG are updated accordingly. - Inspect the output – Open
heart-optimized.svgin a text editor. You should see:<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> <defs> <clipPath id="icon-a"> <path d="M12 21.35L10.55 20.03C5.4 15.36 2 12.28 2 8.5c0-3.86 3.14-7 7-7s7 3.14 7 7c0 3.78-3.4 6.86-8.55 11.53L12 21.35z" /> </clipPath> </defs> <g clip-path="url(#icon-a)"> <path id="icon-b" d="..." fill="red" /> <path id="icon-c" d="..." fill="rgba(0,0,0,0.3)" /> </g> </svg> - Inline the SVG in HTML – Add the optimized SVG directly into your page:
<div class="icon-heart"> <svg ...>…</svg> </div> - Style with CSS – Because the IDs are now predictable, you can target them:
.icon-heart #icon-b { fill: #e91e63; } .icon-heart #icon-c { fill: rgba(0,0,0,0.3); }
File‑Size Impact
Below is a quick comparison for a typical icon set of 50 files. The numbers are illustrative; your actual results will vary based on SVG complexity.
| Metric | Before | After cleanupIDs |
|---|---|---|
| Total size (bytes) | 120,000 | 95,000 |
| Average file size (bytes) | 2,400 | 1,900 |
| Size reduction (%) | N/A | 20% |
Trade‑offs and Limitations
- External CSS/JS breakage – If you have stylesheets or scripts that target the original IDs, they will no longer match. Either update those selectors or keep the original IDs by disabling
cleanupIDsduring development. - Debugging difficulty – Short, non‑semantic IDs make it harder to inspect elements in dev tools. For debugging builds, consider using
keepIdsor a longer prefix. - Prefix collision risk – If you reuse the same prefix across unrelated projects that are later merged, you could still get collisions. Keep prefixes unique to a project or use a hash of the file name.
Integrating into a Build Pipeline
Here’s a quick snippet for a webpack setup that processes all SVGs in src/icons and outputs optimized, prefixed versions into dist/icons:
module.exports = {
module: {
rules: [
{
test: /\.svg$/,
use: [
{
loader: 'svg-sprite-loader',
options: { extract: true }
},
{
loader: 'svgo-loader',
options: {
plugins: [
{ cleanupIDs: { prefixIds: 'icon-', keepIds: false } },
{ removeViewBox: false }
]
}
}
]
}
]
}
};
Running npm run build will now produce a sprite sheet with scoped IDs and a 15‑25% size drop.
Actionable Checklist
- Run
svgo --enable=cleanupIDs --prefixIds='icon-'on your SVG assets. - Verify that all
idreferences still resolve in a test HTML page. - Update any external CSS or JS that relied on original IDs.
- Add the command to your build script or CI pipeline.
- Keep a non‑optimized copy for debugging or when you need human‑readable IDs.
By combining deterministic ID generation with a simple prefix, you keep your SVGs small, collision‑free, and maintainable—exactly what modern front‑end teams need when they inline dozens of icons.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.