SnapDOMGitHub8K
Library Comparison
zumerlab/snapdom

SnapDOM vs html-to-image

Two libraries built around the same SVG foreignObject approach, compared on fidelity, fonts, Shadow DOM, plugins and developer experience.

Feature matrix Migration snippet
TL;DR

html-to-image is a popular, well-maintained fork of dom-to-image with TypeScript support. SnapDOM takes the same idea further with a plugin pipeline, native Shadow DOM walking, and out-of-the-box support for CSS counters, line-clamp and CSS variables.

SnapDOM vs html-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…
html-to-image
Waiting to start…

A quick overview

html-to-image is the most popular community fork of dom-to-image. It modernised the codebase, added TypeScript, and improved fidelity for many edge cases. The API is small and predictable.

SnapDOM is a from-scratch alternative. The capture pipeline is broken into lifecycle hooks (beforeClone, afterClone, beforeRender, afterRender, beforeExport, afterExport), which is what enables its plugin system. Plugins ship for things like CSS filters, color tints, timestamps, ASCII export, PDF export and more.

Feature matrix

FeatureSnapDOMhtml-to-image
Active maintenanceYesYes
Pseudo-elements (::before / ::after)FullYes
Web fonts (@font-face)Embedded + localEmbedded
Shadow DOMNativeManual
CSS variablesYesYes
CSS counter() / counters()YesNo
Line-clamp / multi-line ellipsisYesNo
Plugin systemYes (8+ official)No
Output formatsSVG · PNG · JPG · WebP · Canvas · BlobSVG · PNG · JPG · Canvas · Blob
PDF exportPluginNo
TypeScript typesBundledBundled
LicenseMITMIT

When to use which

Choose SnapDOM when…

  • You use Web Components or Shadow DOM heavily.
  • You need CSS counters or line-clamp ellipsis in the captured output.
  • You want to add filters, watermarks, ASCII or PDF export without forking the library.
  • You need fine-grained font control (embedFonts, localFonts, excludeFonts).

What you give up with html-to-image…

  • No plugin pipeline: watermarks, filters, PDF or ASCII exports are code you write yourself.
  • Shadow DOM needs manual handling; CSS counters and line-clamp aren't captured.
  • No WebP output, and font control stops at a single embed option.

Same task, side by side

Capturing #card as a PNG and inserting the resulting image into the page:

html-to-image

import { toPng } from 'html-to-image';

const dataUrl = await 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);

Migration snippet

html-to-imageSnapDOM
toPng(el)snapdom.toPng(el)
toJpeg(el, { quality: 0.9 })snapdom.toJpg(el, { quality: 0.9 })
toBlob(el)snapdom.toBlob(el)
toCanvas(el)snapdom.toCanvas(el)
toSvg(el)(await snapdom(el)).toSvg()
{ backgroundColor: '#fff' }{ backgroundColor: '#fff' }
{ pixelRatio: 2 }{ dpr: 2 }
{ filter: node => … }{ filter: node => … }
{ fontEmbedCSS }{ embedFonts: true }
not supported{ plugins: [...] }
// Before
import { toPng } from 'html-to-image';
const dataUrl = await toPng(el, { pixelRatio: 2 });

// After
import { snapdom } from '@zumer/snapdom';
const img = await snapdom.toPng(el, { dpr: 2 });

Frequently asked questions

What's actually different between html-to-image and SnapDOM?

Both clone the DOM and render via foreignObject. SnapDOM adds a plugin system with lifecycle hooks, native Shadow DOM walking, CSS counter resolution, line-clamp support, and ships first-party plugins for filters, color tint, timestamp watermark, ASCII export, PDF export and replace-text.

Does SnapDOM render web fonts better than html-to-image?

Both libraries can embed @font-face declarations into the SVG output. SnapDOM exposes embedFonts as a one-line opt-in and additionally supports localFonts and excludeFonts for fine-grained control over which fonts are embedded.

Can I add a watermark or filter without forking the library?

Yes. That's exactly what the SnapDOM plugin system is for. Use the colorTint, filter or timestampOverlay plugins, or write your own with two callbacks (afterClone / beforeExport). Browse the plugins page for the full list.

How do I export to PDF?

Use the pdfImage plugin. It adds a toPdfImage() method to the result object. See the html-to-png how-to for the same pattern with images.

Compare the output

Run both libraries against the same element and compare the output before changing the integration.

Open the demo Install from npm