Guides
Generated SVGs
Convert generated SVG markup to a data URL and display it in an <img>. Medium Zoom attaches to images, so an inline <svg> must be converted before it can zoom.
Open this generated diagram to read it at full size. The SVG includes its own colors, text, and dimensions:
import { ZoomableDiagram } from './zoomable-diagram'
import './generated-diagram.css'
const svg = `
<svg xmlns="http://www.w3.org/2000/svg" width="1440" height="720" viewBox="0 0 1440 720">
<rect width="1440" height="720" rx="24" fill="#f1f5f2" />
<g font-family="system-ui, sans-serif">
<text x="96" y="112" fill="#527361" font-size="24" letter-spacing="4">PUBLISHING WORKFLOW</text>
<text x="96" y="180" fill="#182d23" font-size="48" font-weight="600">From draft to delivery</text>
<path d="M448 390h48m-12-12 12 12-12 12M896 390h48m-12-12 12 12-12 12"
fill="none" stroke="#527361" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" />
<g fill="#fff" stroke="#cedbd2" stroke-width="2">
<rect x="96" y="280" width="352" height="220" rx="20" />
<rect x="496" y="280" width="400" height="220" rx="20" />
<rect x="944" y="280" width="400" height="220" rx="20" />
</g>
<g fill="#527361" font-size="24">
<text x="128" y="332">01</text><text x="528" y="332">02</text><text x="976" y="332">03</text>
</g>
<g fill="#182d23" font-size="36" font-weight="600">
<text x="128" y="402">Write</text><text x="528" y="402">Review</text><text x="976" y="402">Publish</text>
</g>
<g fill="#527361" font-size="24">
<text x="128" y="454">Create a draft</text><text x="528" y="454">Check the details</text><text x="976" y="454">Share with readers</text>
<text x="96" y="614">One clear step at a time.</text>
</g>
</g>
</svg>`
export function GeneratedDiagram() {
return (
<div className="generated-diagram">
<ZoomableDiagram
svg={svg}
alt="Publishing workflow: write a draft, review the details, then publish to readers."
width={1_440}
height={720}
options={{ margin: 32 }}
/>
</div>
)
}.generated-diagram {
width: 100%;
max-width: 560px;
margin: 0 auto;
}
.generated-diagram button[data-slot='image-zoom-trigger'] {
width: 100%;
max-width: 100%;
}The Code view shows the SVG markup and how to pass it to ZoomableDiagram, defined in the React section. For a standalone JavaScript version, see the SVG data URL example and its source (opens in a new tab).
JavaScript
Start with a container such as <div id="diagram"></div>:
import mediumZoom from 'medium-zoom'
const svg = `
<svg xmlns="http://www.w3.org/2000/svg"
width="1440" height="720" viewBox="0 0 1440 720">
<rect width="1440" height="720" fill="#edf2e9" />
<text x="72" y="180" font-family="sans-serif" font-size="64">
A zoomable diagram
</text>
</svg>`
const image = document.createElement('img')
image.alt = 'A zoomable diagram'
image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`
image.style.width = '100%'
image.style.maxWidth = '560px'
image.style.height = 'auto'
const container = document.getElementById('diagram')
if (container) {
container.appendChild(image)
const zoom = mediumZoom(image)
// Before removing the image, detach it from the zoom instance.
// zoom.detach(image)
}For an existing SVG element, serialize its markup with new XMLSerializer().serializeToString(svgElement). Keep the xmlns declaration so the image uses the SVG namespace.
React
After installing the React component, pass the data URL as src. The component manages zoom attachment and cleanup:
import {
ImageZoom,
type ImageZoomProps,
} from '@/components/ui/image-zoom'
type ZoomableDiagramProps = Omit<ImageZoomProps, 'src'> & {
svg: string
}
export function ZoomableDiagram({
svg,
style,
...props
}: ZoomableDiagramProps) {
return (
<ImageZoom
{...props}
src={`data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`}
style={{ width: '100%', maxWidth: 560, height: 'auto', ...style }}
/>
)
}ZoomableDiagramProps keeps the image props, options, and state props from ImageZoomProps, replacing src with the SVG string. Pass alt to describe the diagram.
For Mermaid diagrams, pass the svg string returned by await mermaid.render(...) to this component. If rendering in an effect, ignore results that arrive after the source changes or the component unmounts.
Sizing and image constraints
Set explicit SVG width and height values with a matching viewBox, then display a smaller thumbnail. The example uses a 1440 × 720 SVG displayed at 560 × 280 or smaller.
Data URLs do not match Medium Zoom’s .svg filename check, so zooming uses the image’s natural dimensions, capped by the viewport. A viewBox alone may produce a small natural size.
- Include styles in the SVG. The image cannot inherit the page’s CSS; avoid external fonts and HTML labels. For Mermaid, use SVG text labels (
htmlLabels: false). - Provide meaningful
alttext. Text inside the image is not selectable, and links and event handlers are inactive. - If your site uses Content Security Policy, allow
data:inimg-srcor itsdefault-srcfallback. For example,img-src 'self' data:permits local images and data URLs.