# snapDOM: A Fast and Accurate Tool for Converting Web Elements to Images

In modern web development and design, there’s often a need to save a part of a webpage—a chart, a component, or even the whole page—as an image. This might be for sharing, reports, or documentation. While taking a screenshot is the most direct way, it often falls short when you need high quality, precise control, or automation. This is where tools like snapDOM become invaluable.

snapDOM is a JavaScript library designed for modern web development. Its core function is to quickly and accurately capture any HTML element and convert it into an image. It’s more than just a simple screenshot tool; it’s a powerful and easy-to-integrate solution, especially suited for scenarios requiring high-quality, high-fidelity image output.

## What is snapDOM?

Put simply, snapDOM is a JavaScript library whose primary function is to capture any HTML element on a webpage (including its styles, fonts, background images, and even Shadow DOM) and convert it into an image. It supports exporting to multiple formats, including scalable SVG as well as common formats like PNG, JPG, and WebP. It can also directly output to a <canvas> element.

This tool was initially developed for a view transition framework called Zumly, but its design is very general-purpose, making it easy to apply in various projects.

## Why Choose snapDOM?

Among the many tools available for converting DOM to images, snapDOM stands out due to its unique advantages:

  1. Fast and Accurate: snapDOM is optimized for speed. Its performance, especially when dealing with complex elements, significantly outperforms many similar tools (we’ll provide detailed comparisons later).
  2. High Fidelity: It accurately captures the element’s appearance, including embedded styles, pseudo-elements (like ::before and ::after), fonts, and background images, ensuring the generated image matches what you see on the webpage.
  3. Supports Modern Web Technologies: snapDOM can handle Shadow DOM and Web Components, which is crucial for applications built with modern frontend frameworks like Vue, React, and Angular.
  4. No Dependencies, Built on Standards: It doesn’t rely on any third-party libraries and is built entirely using standard Web APIs provided by browsers, ensuring it’s lightweight and has good compatibility.
  5. Flexible Export Options: It provides multiple convenient methods to convert the capture result directly into an <img> tag, a <canvas>, or a Blob object. It also supports one-click downloading in a specified file format.
  6. Easy to Use: Whether you install it via NPM or include it directly with a <script> tag, integrating snapDOM is very straightforward. Its API design is also intuitive and easy to understand.

## How to Install snapDOM?

Integrating snapDOM into your project is very simple. It supports several mainstream methods of inclusion:

### Using NPM or Yarn (Recommended for Modular Projects)

If your project uses NPM or Yarn for package management, this is the most recommended approach.

# Using NPM
npm install @zumer/snapdom

# Using Yarn
yarn add @zumer/snapdom

### Via CDN (Suitable for Rapid Prototyping or Simple Pages)

If you don’t want to configure a build tool, you can include it directly via a CDN link.

<!-- Include the minified JS file -->
<script src="https://cdn.jsdelivr.net/npm/@zumer/snapdom/dist/snapdom.min.js"></script>

Or, if your project uses ES modules:

<script type="module">
  import { snapdom } from 'https://cdn.jsdelivr.net/npm/@zumer/snapdom/dist/snapdom.mjs';
</script>

### Local Script Inclusion

You can also download the snapDOM files locally and include them using a <script> tag.

<!-- Assuming snapdom.js file is in your project directory -->
<script src="snapdom.js"></script>

For ES modules:

// Assuming snapdom.mjs file is in your project directory
import { snapdom } from './snapdom.mjs';

## How to Use snapDOM?

Using snapDOM is very intuitive. It provides a core snapdom function, along with a series of convenient shortcut methods.

### Basic Usage: Reusable Capture Result

This is the most flexible way to use it, suitable for scenarios where you need to perform multiple different operations on the capture result.

// 1. Select the HTML element you want to capture
const elementToCapture = document.querySelector('#target');

// 2. Call the snapdom function, passing the element and optional configuration options
//    This returns an object containing various export methods
const captureResult = await snapdom(elementToCapture, { scale: 2 });

// 3. Use the returned object to perform actions
//    For example, convert it to a PNG image and insert it into the page
const imgElement = await captureResult.toPng();
document.body.appendChild(imgElement);

//    Or, trigger a download directly
await captureResult.download({ format: 'jpg', filename: 'my-capture' });

### One-Step Shortcut Methods

If you only need to quickly generate and use an image in one specific format, snapDOM provides more concise shortcut methods.

// Select the target element
const el = document.querySelector('#target');

// Generate a PNG image directly and insert it into the page
const pngImage = await snapdom.toPng(el);
document.body.appendChild(pngImage);

// Generate a Blob object directly
const blob = await snapdom.toBlob(el);
// ... The blob can then be used for uploading or other operations

## Core API of snapDOM

The core of snapDOM is the snapdom(el, options?) function, which returns an object containing various export methods.

### Return Value of the Core Function

Calling await snapdom(element, options) will give you an object that contains the following methods:

  • url: (string) The Data URL of the generated SVG image.
  • toRaw(): (string) Returns the raw SVG string.
  • toImg(): (Promise) Returns an <img> element loaded with the SVG.
  • toCanvas(): (Promise) Returns an <canvas> element with the image drawn on it.
  • toBlob(options?): (Promise) Returns a Blob object containing the image data. By default, it’s in SVG format.
  • toPng(options?): (Promise) Returns an <img> element containing the PNG image.
  • toJpg(options?): (Promise) Returns an <img> element containing the JPG image.
  • toWebp(options?): (Promise) Returns an <img> element containing the WebP image.
  • download(options?): (Promise) Triggers the browser to download the generated image file.

### Shortcut Methods

For convenience, snapDOM also mounts a series of static methods directly on the snapdom object. These methods accept the element and options as arguments directly:

Method Description
snapdom.toImg(el, options?) Returns an <img> element
snapdom.toCanvas(el, options?) Returns a <canvas> element
snapdom.toBlob(el, options?) Returns an SVG Blob object
snapdom.toPng(el, options?) Returns a PNG image <img> element
snapdom.toJpg(el, options?) Returns a JPG image <img> element
snapdom.toWebp(el, options?) Returns a WebP image <img> element
snapdom.download(el, options?) Triggers a download of the image file in the specified format

### Configuration Options (Options)

snapDOM provides rich configuration options, allowing you to finely control the capture and export process. All capture methods (both the core function and shortcut methods) accept an options object as the second parameter.

Option Type Default Description
compress boolean true Whether to remove redundant styles to reduce the size of the generated image.
fast boolean true Whether to skip idle delay for faster results.
embedFonts boolean false Whether to inline regular fonts (icon fonts are always inlined).
scale number 1 The output image scale multiplier. For example, scale: 2 generates an image twice the size, often used to improve clarity.
width number - Specific width (in pixels) for the output image.
height number - Specific height (in pixels) for the output image.
backgroundColor string "#fff" Background color for JPG/WebP formats (as these formats don’t support transparency).
quality number 1 Image quality for JPG/WebP formats, ranging from 0 to 1.
useProxy string '' Specifies a proxy server address to handle failed cross-origin (CORS) image loading.
type string "svg" Specifies the Blob type returned by the toBlob method (e.g., "png", "jpg", "webp").
exclude string[] - An array of CSS selectors to specify child elements that should be excluded from the capture.
filter function - A custom filter function, e.g., (el) => !el.classList.contains('hidden'), for more flexible control over including or excluding elements.

### Setting Custom Dimensions (width and height)

Using the width and height options allows you to generate images with specific dimensions.

  1. Fixed Width (Proportional Height)
    Sets a specific width while the height adjusts automatically according to the original element’s aspect ratio.

    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 the width adjusts automatically according to the original element’s aspect ratio.

    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 the image to stretch to the specified dimensions. If the ratio differs from the original element, it may distort the image.

    const result = await snapdom(element, {
      width: 800,
      height: 200 // Outputs an 800px × 200px image (may stretch/squish content)
    });
    

    Important Note: If the scale option is not 1, it takes priority over width and height. For example, { scale: 3, width: 500 } will ignore width and scale the image 3x instead.

### Handling Cross-Origin Images (Cross-Origin Images)

When an element contains images from other domains, the browser’s security policy (CORS) might prevent snapDOM from loading these images. snapDOM attempts by default to load images using crossOrigin="anonymous" or crossOrigin="use-credentials". If loading fails, you can use the useProxy option to specify a proxy server to resolve this issue.

const result = await snapdom(element, {
  // Example proxy server (please replace with your own or a reliable public proxy)
  useProxy: 'https://corsproxy.io/?url='
  // Or: useProxy: 'https://api.allorigins.win/raw?url='
});

### Download Options (Download Options)

The download method (and the snapdom.download shortcut method) accepts a configuration object to control the download behavior:

{
  format?: "svg" | "png" | "jpg" | "jpeg" | "webp"; // default: "png"
  filename?: string;         // default: "capture"
  backgroundColor?: string;  // optional override
}

For example:

await captureResult.download({
  format: 'webp',
  filename: 'screenshot',
  backgroundColor: '#f0f0f0'
});

### Optional Helper Function: preCache()

For complex elements containing a large number of external resources (such as images and fonts), the preCache() function can preload these resources before the actual capture, thereby improving the speed and success rate of the capture.

import { preCache } from '@zumer/snapdom';

// Preload resources for the entire page before capturing
await preCache(document.body);

// Or preload after the page has loaded
import { snapdom, preCache } from './snapdom.mjs';
window.addEventListener('load', async () => {
  await preCache();
  console.log('📦 Resources preloaded');
});

Options for preCache():

  • embedFonts (boolean, default: true): Whether to inline non-icon fonts during preloading.
  • reset (boolean, default: false): Whether to clear all existing internal caches.
  • useProxy (string): Proxy server address for handling CORS images.

## Core Features and Capabilities of snapDOM

snapDOM is powerful because it supports many key modern web features:

  • Capturing Shadow DOM and Web Components: Modern frontend frameworks widely use Shadow DOM to encapsulate component styles and structure. snapDOM can delve into it and accurately capture its content.
  • Support for Pseudo-elements: Pseudo-elements like ::before, ::after, and ::first-letter are often used to add decorative content. snapDOM ensures they are correctly included in the image.
  • Inlining Background Images and Fonts: To ensure the independence and portability of the image, snapDOM inlines the background images and fonts (including icon fonts like Font Awesome, Material Icons) used by the element into the generated SVG.
  • Element Exclusion and Placeholders:

    • You can tell snapDOM to ignore an element by adding the data-capture="exclude" attribute to it.
    • For elements containing sensitive information, you can use data-capture="placeholder" along with data-placeholder-text="Replacement Text" to replace its content with specified text, achieving a masking effect.

## Limitations and Considerations

Despite its powerful features, there are a few points to keep in mind when using snapDOM:

  • CORS Issues with External Images: As mentioned earlier, cross-origin images require proper CORS configuration or the use of a proxy.
  • Iframes are Not Supported: For security and complexity reasons, snapDOM cannot capture the content inside an <iframe>.
  • Safari Support for WebP: When using the WebP format in Safari browsers, snapDOM will automatically fall back to rendering in PNG format.
  • @font-face and FontFace(): snapDOM has good support for the CSS @font-face rule. However, if you use the FontFace() API in JavaScript to dynamically load fonts, you might need to refer to the workaround mentioned in issue #43.

## Performance Benchmarks

snapDOM has undergone significant performance optimizations, especially since version v1.8.0, with a notable performance boost.

Comparison with Simple Elements

Scenario (Dimensions) 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

Comparison with Complex Elements

Scenario (Dimensions) 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

Summary

  • The current version of snapDOM is 2 to 6 times faster than v1.8.0.
  • It’s up to 150 times faster than html2canvas.
  • It’s up to 8 times faster than html-to-image in large scenarios.

(Benchmarks run in Chromium using Vitest. Hardware: MacBook Air 2018. Actual performance may vary depending on the device and browser.)

If you’d like to verify these performance data yourself, you can clone the snapDOM code repository and run the benchmarks:

git clone https://github.com/zumerlab/snapdom.git
cd snapdom
npm install
npm run test:benchmark

## Development and Contribution

snapDOM is an open-source project, and developers are welcome to contribute. If you want to delve into its internal implementation or contribute code, you can follow these steps for local development:

  1. Clone the repository: git clone https://github.com/zumerlab/snapdom.git
  2. Switch to the development branch: git checkout dev
  3. Install dependencies: npm install
  4. Compile the library: npm run compile (Generates ESM, CJS, and minified versions to the dist/ directory)
  5. Install test browsers: npx playwright install (Required for running tests)
  6. Run tests: npm test
  7. Run benchmarks: npm run test:benchmark

The source code is located in the src/ directory. Detailed contribution guidelines can be found in CONTRIBUTING.md.

## Conclusion

snapDOM is a powerful, fast, and easy-to-use DOM-to-image conversion tool. Thanks to its deep support for modern web standards, outstanding performance, and flexible API, it has become a very valuable addition to a frontend developer’s toolkit. Whether you need to add screenshot functionality to your application or automate the generation of high-quality documentation images, snapDOM can provide a reliable and efficient solution.

snapDOM Hero Image