SnapDOMGitHub★ 8K
Live demo

Live element

Hard parts

transform + shadow

Result

Nothing captured yet

Edit the title, then run. This uses the real library from unpkg.
Library Comparison

SnapDOM vs dom-to-image

Compare the original dom-to-image API with SnapDOM: rendering approach, plugin exports and the return types to change during migration.

TL;DR

dom-to-image uses SVG foreignObject to capture the DOM. SnapDOM uses that rendering approach with support for open Shadow DOM, CSS counters and a plugin lifecycle.

SnapDOM vs dom-to-image, head to head

Both libraries export the same DOM element to PNG five times. Times are averaged, the faster one is highlighted. Run it on your machine — the gap is hardware- and content-dependent.

Test element to be captured by both libraries.
SnapDOM
Waiting to start…
dom-to-image
Waiting to start…

A quick overview

dom-to-image clones a node, inlines CSS and assets, and wraps it in a <foreignObject> for the browser to render. Its API returns image data URLs or a PNG Blob. Check its repository for current releases and supported browsers.

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 alter capture state, observe exports, and add custom exporters without forking the library.

Feature matrix

FeatureSnapDOMdom-to-image
Release historySee repositorySee repository
Pseudo-elements (::before / ::after)SupportedPasses tested fixture
Web fonts (@font-face)EmbeddedEmbedded
Shadow DOMOpen rootsNo
CSS variablesYesPartial
CSS counter() / counters()YesDepends on the case
Line-clamp / multi-line ellipsisYesDepends on the case
Plugin systemYesNo
Output formatsSVG · PNG · JPG · WebP · Canvas · BlobSVG · PNG · JPG · Blob
ES Module buildYesCommonJS
TypeScript typesBundledDefinitelyTyped
LicenseMITMIT

Support varies by fixture and rendering mode; test your own UI. See the live benchmark for its pixel fixtures and loaded versions.

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.

Check before migrating…

  • Compare captures of your layouts in each browser you support.
  • Test web fonts, open Shadow DOM, CSS counters and line-clamp with your content.
  • CommonJS-era packaging and no bundled TypeScript types.

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

Match both the output format and return type. A dom-to-image filter includes nodes when true; SnapDOM exclude removes them when true. SnapDOM width and height size the output rather than reflowing the source layout:

dom-to-imageSnapDOM
domtoimage.toPng(el)(await snapdom.toPng(el)).src
domtoimage.toJpeg(el, { quality: 0.9 })(await snapdom.toJpg(el, { quality: 0.9 })).src
domtoimage.toBlob(el)snapdom.toBlob(el, { format: 'png' })
domtoimage.toSvg(el)snapdom.toRaw(el)
{ bgcolor: '#fff' }{ backgroundColor: '#fff' }
{ width, height }{ width, height } (output size)
{ filter: keep }{ exclude: node => !keep(node) }
— (not supported){ embedFonts: 'auto' } (default)
— (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?

Check the dom-to-image repository for its release history and open issues. Before migrating, compare your captured output and account for the return-type and option differences shown above.

How do I migrate from dom-to-image to SnapDOM?

Import @zumer/snapdom and start with snapdom.toPng(element). Read .src on the returned image if the caller expects a PNG data URL. Rename bgcolor to backgroundColor, invert inclusion predicates for exclude, and review output sizing.

Does SnapDOM support custom fonts?

Yes. In v3, embedFonts: 'auto' embeds used web fonts by default. Font files must be accessible; localFonts and excludeFonts give additional control.

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 Installation