dom-to-image was the first library to popularise the SVG foreignObject trick for capturing the DOM, but its original package hasn't been actively maintained for years. SnapDOM picks up the same approach, modernises it, and adds web fonts, Shadow DOM, plugins and full pseudo-element support.
A quick overview
dom-to-image introduced the technique most modern libraries still use: clone the node, inline its CSS and assets, wrap it in a <foreignObject>, and let the browser do the painting. It works, it's small, and the API is friendly. The downside is that it stopped receiving meaningful updates, so newer CSS features and edge cases are gradually catching up to it.
SnapDOM is a from-scratch implementation of the same idea, with active development and a plugin system on top. The capture pipeline is exposed through lifecycle hooks (beforeClone, afterClone, beforeRender, afterRender, beforeExport, afterExport) so you can transform the result without forking the library.
Feature matrix
| Feature | SnapDOM | dom-to-image |
|---|---|---|
| Active maintenance | Yes | Stalled |
Pseudo-elements (::before / ::after) | Full | Limited |
Web fonts (@font-face) | Embedded | Best-effort |
| Shadow DOM | Yes | No |
| CSS variables | Yes | Partial |
CSS counter() / counters() | Yes | No |
| Line-clamp / multi-line ellipsis | Yes | No |
| Plugin system | Yes | No |
| Output formats | SVG · PNG · JPG · WebP · Canvas · Blob | SVG · PNG · JPG · Blob |
| ES Module build | Yes | CommonJS |
| TypeScript types | Bundled | DefinitelyTyped |
| License | MIT | MIT |
When to use which
Choose SnapDOM when…
- You need active maintenance and bug fixes.
- Your UI depends on modern CSS features (variables, pseudo-elements, line-clamp).
- You use Web Components or Shadow DOM.
- You want to add custom export formats or transformations through plugins.
- You need first-class TypeScript types out of the box.
dom-to-image might still fit when…
- You're maintaining a legacy CommonJS project that's already using it and works fine.
- Your captures are simple and you prefer not to introduce any new dependencies.
Same task, side by side
Capturing #card as a PNG and inserting the resulting image into the page:
dom-to-image
import domtoimage from 'dom-to-image'; const dataUrl = await domtoimage.toPng(document.querySelector('#card')); const img = new Image(); img.src = dataUrl; document.body.appendChild(img);
SnapDOM
import { snapdom } from '@zumer/snapdom'; const img = await snapdom.toPng(document.querySelector('#card')); document.body.appendChild(img);
SnapDOM returns the HTMLImageElement directly so you can drop the data-URL plumbing.
Migration snippet
Most dom-to-image options have a direct SnapDOM equivalent:
| dom-to-image | SnapDOM |
|---|---|
| domtoimage.toPng(el) | snapdom.toPng(el) |
| domtoimage.toJpeg(el, { quality: 0.9 }) | snapdom.toJpg(el, { quality: 0.9 }) |
| domtoimage.toBlob(el) | snapdom.toBlob(el) |
| domtoimage.toSvg(el) | (await snapdom(el)).toSvg() |
| { bgcolor: '#fff' } | { backgroundColor: '#fff' } |
| { width, height } | { width, height } |
| { filter: node => … } | { filter: node => … } |
| — (not supported) | { embedFonts: true } |
| — (not supported) | { plugins: [...] } |
// Before import domtoimage from 'dom-to-image'; const dataUrl = await domtoimage.toPng(el, { bgcolor: '#fff' }); // After import { snapdom } from '@zumer/snapdom'; const img = await snapdom.toPng(el, { backgroundColor: '#fff' });
Frequently asked questions
Is dom-to-image still maintained?
The original dom-to-image package on npm has not received a release in years. The community-maintained fork dom-to-image-more is more active, and html-to-image is another popular fork. SnapDOM is a from-scratch alternative under active development.
How do I migrate from dom-to-image to SnapDOM?
Replace the import with @zumer/snapdom and call snapdom.toPng(element). Most options (filter, bgcolor, width, height, style) have a direct SnapDOM equivalent — see the migration table above.
Does SnapDOM support custom fonts?
Yes. Pass { embedFonts: true } and the matching @font-face declarations are inlined into the SVG output, so the captured image renders with your real fonts.
What about Shadow DOM?
Open Shadow DOM trees are walked and cloned by SnapDOM, so Web Components capture correctly. dom-to-image does not natively support this.
Ready to switch?
Drop SnapDOM into your project and capture your first element in seconds.
Open the demo Install from npm