Base64 SVG Not Displaying? A Practical, Engineering-Ready Fix
This issue shows up in real projects all the time:
- Your
img src="data:image/svg+xml;base64,..."looks valid, but nothing renders. - The same SVG string works in one place and breaks in a CSS background.
- The bug is hard to spot in code review, but expensive to debug.
If this sounds familiar, this guide gives you a repeatable fix path.
Why This Is Hard to Debug
The issue is rarely one broken line. It is usually a chain problem:
- The SVG source may already be invalid.
- The encoding may not match the target context.
- HTML, CSS, and JSON each require different escaping behavior.
- Security cleanup and rendering rules vary by environment.
That is why one SVG can render in one context and fail in another.
Most Common Root Causes (In Priority Order)
-
Wrong MIME prefix
Usedata:image/svg+xml;base64,ordata:image/svg+xml,. -
Incorrect Base64 encoding flow
Directbtoa(svg)can break when the SVG contains non-ASCII characters. -
Escaping mismatches across contexts
In CSS especially, characters like#and quotes can break loading. -
Risky or blocked SVG content
Scripts, event handlers, and external references may be removed or blocked. -
Broken SVG structure
MissingviewBox, malformed XML, or invalid tags can prevent rendering.
How We Solve This in SVGView
Instead of asking users to guess, we handle it in three layers.
1) Input Layer: Validate Before Import
In src/lib/svg/import-handler.ts, we:
- enforce file type and size (up to 10MB)
- parse and validate XML with a required
<svg>root - return parse errors for faster diagnosis
This removes invalid input early.
2) Safety Layer: Sanitize Before Preview
In src/lib/svg/sanitizer.ts, we remove:
<script>on*event handler attributes<foreignObject>- external refs (
href,xlink:href,src)
This improves security and reduces rendering inconsistency.
3) Output Layer: Provide Both Base64 and URL-Encoded Data URI
In src/lib/svg/exporter.ts:
export function exportToDataUri(svg: string): string {
const encoded = btoa(unescape(encodeURIComponent(svg)));
return `data:image/svg+xml;base64,${encoded}`;
}
export function exportToDataUriEncoded(svg: string): string {
const encoded = encodeURIComponent(svg);
return `data:image/svg+xml,${encoded}`;
}
So you can:
- choose Base64 for safer compatibility
- choose URL encoding for shorter, readable output
- always get the correct
image/svg+xmlMIME type
Which Encoding Should You Use?
- Unknown target environment: choose Base64 first
- Need shorter and readable strings: choose URL encoding
- CSS background usage: prefer URL encoding with proper escaping
Use these tools directly:
A Repeatable Troubleshooting Checklist
- Confirm prefix:
data:image/svg+xml;base64,ordata:image/svg+xml, - Confirm a valid
<svg>root andviewBox - Confirm UTF-8-safe encoding flow
- Confirm escaping for CSS/JSON contexts
- Sanitize before export
- Switch Base64 and URL encoding to cross-check quickly
FAQ
Why does it work in <img> but fail in CSS?
Because CSS string parsing has stricter escaping requirements. URL encoding is usually safer there.
Is changing to image/svg+xml always enough?
No. MIME is only one part. Encoding, escaping, and SVG validity still matter.
Is Data URI always better than external SVG files?
No. Data URI is great for small inline assets. Large or heavily reused assets are often better as external files.
Summary
“Base64 SVG not displaying” is not a single bug. It is a pipeline problem.
Once you standardize the flow as validate -> sanitize -> dual encoding -> context match, the issue becomes predictable and manageable.