snapDOM captures HTML elements to images with exceptional speed and accuracy.
npm install @mindblowing/snapdomsnapDOM is a fast and accurate DOM-to-image capture tool built for Zumly, a zoom-based view transition framework.
It captures any HTML element as a scalable SVG image, preserving styles, fonts, background images, pseudo-elements, and even shadow DOM. It also supports export to raster image formats and canvas.
* šø Full DOM capture
* šØ Embedded styles, pseudo-elements, and fonts
* š¼ļø Export to SVG, PNG, JPG, WebP, or canvas
* ā” Ultra fast, no dependencies
* š¦ 100% based on standard Web APIs
https://zumerlab.github.io/snapdom/
``sh`
npm i @zumer/snapdom
`sh`
yarn add @zumer/snapdom
`html`
`html`
`js`
import { snapdom } from './snapdom.mjs';
`html`
`js
const el = document.querySelector('#target');
const result = await snapdom(el, { scale: 2 });
const img = await result.toPng();
document.body.appendChild(img);
await result.download({ format: 'jpg', filename: 'my-capture' });
`
`js
const el = document.querySelector('#target');
const png = await snapdom.toPng(el);
document.body.appendChild(png);
const blob = await snapdom.toBlob(el);
`
Returns an object with reusable export methods:
`js`
{
url: string;
toRaw(): string;
toImg(): Promise
toCanvas(): Promise
toBlob(): Promise
toPng(): Promise
toJpg(options?): Promise
toWebp(options?): Promise
download(options?): Promise
}
| Method | Description |
| ------------------------------ | ------------------------------------- |
| snapdom.toImg(el, options?) | Returns an HTMLImageElement |snapdom.toCanvas(el, options?)
| | Returns a Canvas |snapdom.toBlob(el, options?)
| | Returns an SVG 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 download in specified format |
All capture methods accept an options object:
| Option | Type | Default | Description |
| ----------------- | -------- | -------- | ------------------------------------------ |
| compress | boolean | true | Removes redundant styles |fast
| | boolean | true | Skips idle delay for faster results |embedFonts
| | boolean | false | Inlines fonts (icon fonts always embedded) |scale
| | number | 1 | Output scale multiplier |width
| | number | - | Output specific width size |height
| | number | - | Output specific height size |backgroundColor
| | string | "#fff" | Fallback color for JPG/WebP |quality
| | number | 1 | Quality for JPG/WebP (0 to 1) |useProxy
| | string | '' | Specify a proxy for handling CORS images as fallback|type
| | string | svg | Select png, jpg, webp Blob type|exclude
| | string[] | - | CSS selectors for elements to exclude |filter
| | function | - | Custom filter function ie (el) => !el.classList.contains('hidden') |
Use the width and height options to generate an image with specific dimensions.
Examples:
1. Fixed width (proportional height)
Sets a specific width while maintaining the aspect ratio. Height adjusts proportionally.
`js`
const result = await snapdom(element, {
width: 400 // Outputs a 400px-wide image with auto-scaled height
});
2. Fixed height (proportional width)
Sets a specific height while maintaining the aspect ratio. Width adjusts proportionally.
`js`
const result = await snapdom(element, {
height: 200 // Outputs a 200px-tall image with auto-scaled width
});
3. Fixed width and height (may distort image)
Forces exact dimensions, potentially distorting the image if the aspect ratio differs.
`js`
const result = await snapdom(element, {
width: 800, // Outputs an 800px Ć 200px image (may stretch/squish content)
height: 200
});
Note: If scale is different from 1, it takes priority over width and height.{ scale: 3, width: 500 }
Example: ignores width and scales the image 3x instead.
By default, snapDOM loads images with crossOrigin="anonymous" or crossOrigin="use-credentials". In case fails to get the images, useProxy can be used to deal with CORS images:
`js`
const result = await snapdom(element, {
useProxy: 'your/proxy/' //Example: 'https://corsproxy.io/?url=' or 'https://api.allorigins.win/raw?url='
});
`js`
{
format?: "svg" | "png" | "jpg" | "jpeg" | "webp"; // default: "png"
filename?: string; // default: "capture"
backgroundColor?: string; // optional override
}
The preCache() function can be used to load external resources (like images and fonts) in advance. It is specially useful when the element to capure is big and complex.
`js
import { preCache } from '@zumer/snapdom';
await preCache(document.body);
`
`js`
import { snapdom, preCache } from './snapdom.mjs';
window.addEventListener('load', async () => {
await preCache();
console.log('š¦ Resources preloaded');
});
Options for preCache():
embedFonts (boolean, default: true)* ā Inlines non-icon fonts during preload.
reset (boolean, default: false)* ā Clears all existing internal caches.
useProxy (string)* ā Proxy for handling CORS images as fallback.
* Captures shadow DOM and Web Components
* Supports ::before, ::after and ::first-letter pseudo-elementsdata-capture="exclude"
* Inlines background images and fonts
* Handles Font Awesome, Material Icons, and more
* to ignore an elementdata-capture="placeholder"
* with data-placeholder-text for masked replacements
* External images shloud be CORS-accessible (use useProxy option for handling CORS denied)@font-face
* Iframes are not supported
* When WebP format is used on Safari, it will fallback to PNG rendering.
* CSS rule is well supported, but if need to use JS FontFace(), see this workaround #43
Snapdom has received significant performance improvements since version v1.8.0. The following benchmarks compare:
* Snapdom (current)
* Snapdom v1.8.0
* html2canvashtml-to-image
*
| Scenario | Snapdom (current) | Snapdom v1.8.0 | html2canvas | html-to-image |
| ------------------------ | ----------------- | -------------- | ----------- | ------------- |
| Small (200Ć100) | 0.4 ms | 1.2 ms | 70.3 ms | 3.6 ms |
| Modal (400Ć300) | 0.4 ms | 1.1 ms | 68.8 ms | 3.6 ms |
| Page View (1200Ć800) | 0.4 ms | 1.0 ms | 100.5 ms | 3.4 ms |
| Large Scroll (2000Ć1500) | 0.4 ms | 1.0 ms | 153.1 ms | 3.4 ms |
| Very Large (4000Ć2000) | 0.4 ms | 1.0 ms | 278.9 ms | 4.3 ms |
| Scenario | Snapdom (current) | Snapdom v1.8.0 | html2canvas | html-to-image |
| ------------------------ | ----------------- | -------------- | ----------- | ------------- |
| Small (200Ć100) | 1.1 ms | 3.2 ms | 76.0 ms | 15.3 ms |
| Modal (400Ć300) | 4.5 ms | 14.0 ms | 133.2 ms | 55.4 ms |
| Page View (1200Ć800) | 32.9 ms | 113.6 ms | 303.4 ms | 369.1 ms |
| Large Scroll (2000Ć1500) | 133.9 ms | 387.4 ms | 594.4 ms | 1,163.0 ms |
| Very Large (4000Ć2000) | 364.0 ms | 1,200.4 ms | 1,380.8 ms | 3,023.9 ms |
* Snapdom (current) is 2Ćā6Ć faster than v1.8.0html2canvas
* Up to 150Ć faster than html-to-image
* Up to 8Ć faster than in large scenarios
Benchmarks run in Chromium using Vitest.
Hardware: MacBook Air 2018.
ā ļø Performance may vary depending on device.
`sh`
git clone https://github.com/zumerlab/snapdom.git
cd snapdom
npm install
npm run test:benchmark
To contribute or build snapDOM locally:
`shClone the repository
git clone https://github.com/zumerlab/snapdom.git
cd snapdom
The main entry point is in
src/, and output bundles are generated in the dist/` folder.For detailed contribution guidelines, please see CONTRIBUTING.
Special thanks to @megaphonecolin for supporting this project!
If you'd like to support this project too, you can become a sponsor.
MIT Ā© Zumerlab