English | 简体中文
SnapDOM is a next-generation DOM Capture Engine — the fast, modern alternative to html2canvas, dom-to-image, and html-to-image.
It converts any DOM subtree into a self-contained representation that can be exported to SVG, PNG, JPG, WebP, Canvas, Blob, or any custom format through plugins — ultra-fast, modular, extensible, and dependency-free.
canvas, or Blobìframe... line-clampCapture any DOM element to PNG in one line:
import { snapdom } from '@zumer/snapdom';
const img = await snapdom.toPng(document.querySelector('#card'));
document.body.appendChild(img);
Reusable capture (one clone, multiple exports):
const result = await snapdom(document.querySelector('#card'));
await result.toPng(); // → HTMLImageElement
await result.toSvg(); // → SVG as Image
await result.download({ format: 'jpg', filename: 'card.jpg' });
SnapDOM transforms your DOM element through these stages:
DOM Element
↓
Clone
↓
Styles & Pseudo
↓
Images & Backgrounds
↓
Fonts
↓
SVG foreignObject
↓
data:image/svg+xml
↓
toPng / toSvg / toBlob / download
| Stage | What happens |
|---|---|
| Clone | Deep clone with styles, Shadow DOM, iframes. Exclude/filter nodes. |
| Styles & Pseudo | Inline ::before/::after as elements, resolve counter()/counters(). |
| Images & Backgrounds | Fetch and inline external images/backgrounds as data URLs. |
| Fonts | Embed @font-face (optional) and icon fonts. |
| SVG | Wrap clone in <foreignObject>, serialize to data:image/svg+xml. |
| Export | Convert SVG to PNG/JPG/WebP/Blob or trigger download. |
Plugin hooks: beforeSnap → beforeClone → afterClone → beforeRender → afterRender → beforeExport → afterExport.
<img> load failurescale, width, height)useProxy)exclude vs filternpm i @zumer/snapdom
yarn add @zumer/snapdom
For early access to new features and fixes:
npm i @zumer/snapdom@dev
yarn add @zumer/snapdom@dev
⚠️ The @dev tag usually includes improvements before they reach production, but may be less stable.
<script src="https://unpkg.com/@zumer/snapdom/dist/snapdom.js"></script>
<script type="module">
import { snapdom } from "https://unpkg.com/@zumer/snapdom/dist/snapdom.mjs";
</script>
<script src="https://unpkg.com/@zumer/snapdom@dev/dist/snapdom.js"></script>
<script type="module">
import { snapdom } from "https://unpkg.com/@zumer/snapdom@dev/dist/snapdom.mjs";
</script>
| Variant | File | Use case |
|---|---|---|
| ESM (tree-shakeable) | dist/snapdom.mjs |
Bundlers (Vite, webpack), import |
| IIFE (global) | dist/snapdom.js |
Script tag, legacy require |
Bundler (npm):
import { snapdom } from '@zumer/snapdom'; // → dist/snapdom.mjs
Script tag (CDN):
<script src="https://unpkg.com/@zumer/snapdom/dist/snapdom.js"></script>
<script> snapdom.toPng(document.body).then(img => document.body.appendChild(img)); </script>
Subpath imports (lighter bundle if you only need one):
import { preCache } from '@zumer/snapdom/preCache';
import { plugins } from '@zumer/snapdom/plugins';
| Pattern | When to use |
|---|---|
Reusable snapdom(el) |
One clone → many exports (PNG + JPG + download). |
Shortcuts snapdom.toPng(el) |
Single export, less code. |
Capture once, export many times (no re-clone):
const el = document.querySelector('#target');
const result = await snapdom(el);
const img = await result.toPng();
document.body.appendChild(img);
await result.download({ format: 'jpg', filename: 'my-capture.jpg' });
Direct export when you need a single format:
const png = await snapdom.toPng(el);
const blob = await snapdom.toBlob(el);
document.body.appendChild(png);
snapdom(el, options?)Returns an object with reusable export methods:
{
url: string;
toRaw(): string;
toImg(): Promise<HTMLImageElement>; // deprecated
toSvg(): Promise<HTMLImageElement>;
toCanvas(): Promise<HTMLCanvasElement>;
toBlob(options?): Promise<Blob>;
toPng(options?): Promise<HTMLImageElement>;
toJpg(options?): Promise<HTMLImageElement>;
toWebp(options?): Promise<HTMLImageElement>;
download(options?): Promise<void>;
}
| Method | Description |
|---|---|
snapdom.toImg(el, options?) |
Returns an SVG HTMLImageElement (deprecated) |
snapdom.toSvg(el, options?) |
Returns an SVG HTMLImageElement |
snapdom.toCanvas(el, options?) |
Returns a Canvas |
snapdom.toBlob(el, options?) |
Returns an SVG or raster Blob |
snapdom.toPng(el, options?) |
Returns a PNG image |
snapdom.toJpg(el, options?) |
Returns a JPG image |
snapdom.toWebp(el, options?) |
Returns a WebP image |
snapdom.download(el, options?) |
Triggers a download |
Some exporters accept a small set of export-only options in addition to the global capture options.
download()| Option | Type | Default | Description |
|---|---|---|---|
filename |
string |
snapdom |
Download name. |
format |
"png" \| "jpeg" \| "jpg" \| "webp" \| "svg" |
"png" |
Output format for the downloaded file. |
Example:
await result.download({
format: 'jpg',
quality: 0.92,
filename: 'my-capture'
});
toBlob()| Option | Type | Default | Description |
|---|---|---|---|
type |
"svg" \| "png" \| "jpeg" \| "jpg" \| "webp" |
"svg" |
Blob type to generate. |
Example:
const blob = await result.toBlob({ type: 'jpeg', quality: 0.92 });
All capture methods accept an options object:
| Option | Type | Default | Description |
|---|---|---|---|
debug |
boolean | false |
When true, logs suppressed errors to console.warn for troubleshooting |
fast |
boolean | true |
Skips small idle delays for faster results |
embedFonts |
boolean | false |
Inlines non-icon fonts (icon fonts always on) |
localFonts |
array | [] |
Local fonts { family, src, weight?, style? } |
iconFonts |
string|RegExp|Array | [] |
Extra icon font matchers |
excludeFonts |
object | {} |
Exclude families/domains/subsets during embedding |
scale |
number | 1 |
Output scale multiplier |
dpr |
number | devicePixelRatio |
Device pixel ratio |
width |
number | - | Output width |
height |
number | - | Output height |
backgroundColor |
string | "#fff" |
Fallback color for JPG/WebP |
quality |
number | 1 |
Quality for JPG/WebP (0 to 1) |
useProxy |
string | '' |
Proxy base for CORS fallbacks |
exclude |
string[] | - | CSS selectors to exclude |
excludeMode |
"hide"|"remove" |
"hide" |
How exclude is applied |
filter |
function | - | Custom predicate (el) => boolean |
filterMode |
"hide"|"remove" |
"hide" |
How filter is applied |
cache |
string | "soft" |
disabled | soft | auto | full |
placeholders |
boolean | true |
Show placeholders for images/CORS iframes |
fallbackURL |
string | function | - | Fallback image for <img> load failure |
outerTransforms |
boolean | true |
When false removes translate/rotate but preserves scale/skew, producing a flat, reusable capture |
outerShadows |
boolean | false |
Do not expand the root’s bounding box for shadows/blur/outline, and strip those visual effects from the cloned root |
safariWarmupAttempts |
number | 3 |
Safari only: iterations to prime font/decode (WebKit #219770). Use 1 if 3 causes lag |
When debug: true, SnapDOM logs normally suppressed errors to console.warn (with the [snapdom] prefix). Useful for troubleshooting capture issues (canvas failures, blob resolution, style stripping, etc.) without noisy output in production.
await snapdom.toPng(el, { debug: true });
<img> load failureProvide a default image for failed <img> loads. You can pass a fixed URL or a callback that receives measured dimensions and returns a URL (handy to generate dynamic placeholders).
// 1) Fixed URL fallback
await snapdom.toSvg(element, {
fallbackURL: '/images/fallback.png'
});
// 2) Dynamic placeholder via callback
await snapdom.toSvg(element, {
fallbackURL: ({ width: 300, height: 150 }) =>
`https://placehold.co/${width}x${height}`
});
// 3) With proxy (if your fallback host has no CORS)
await snapdom.toSvg(element, {
fallbackURL: ({ width = 300, height = 150 }) =>
`https://dummyimage.com/${width}x${height}/cccccc/666.png&text=img`,
useProxy: 'https://proxy.corsfix.com/?'
});
Notes:
- If the fallback image also fails to load, snapDOM replaces the <img> with a placeholder block preserving width/height
$ claude mcp add snapdom \
-- python -m otcore.mcp_server <graph>