SnapDOMGitHub★ 8K
Live demo

Live element

Component preview
Capture an editable component
1,284+12% vs last week

Editable text and an open shadow root can be captured together.

Result

Nothing captured yet

Edit the title, then run. This uses the real library from unpkg.
How-To Recipe

How to convert HTML to PNG in JavaScript

Three patterns: append the image to the page, download it as a file, or get a Blob to upload. Pick the one that fits your use case and copy the snippet.

TL;DR

const img = await snapdom.toPng(element); — that returns an HTMLImageElement. Append it, download it, or convert to a Blob with snapdom.toBlob(element, { format: 'png' }) if you need a PNG Blob to upload.

Choose the PNG output you need

This recipe starts with an element already rendered in the browser and focuses on the output: an image for a preview, a file to download, or a Blob for an upload. To select an element and prepare its layout first, start with Screenshot a div.

toPng() returns an HTMLImageElement; toBlob(el, { format: 'png' }) returns a PNG Blob. download() saves a file. Choose the path below for the value your application actually needs.

Step 1 — Install

npm install @zumer/snapdom@latest

Or load it from a CDN if you don't use a bundler:

<script type="module">
  import { snapdom } from "https://unpkg.com/@zumer/snapdom@latest/dist/snapdom.mjs";
</script>

Pattern 1 — Append the PNG to the page

Useful for quick previews and demos. snapdom.toPng returns an HTMLImageElement, ready to insert anywhere in the DOM:

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

const img = await snapdom.toPng(document.querySelector('#card'));
document.body.appendChild(img);

Pattern 2 — Download the PNG as a file

SnapDOM ships with a one-liner that triggers the browser's download flow:

const result = await snapdom(document.querySelector('#card'));
await result.download({ format: 'png', filename: 'card' });

If you need more control, build the download yourself with a Blob and an anchor tag:

const blob = await snapdom.toBlob(document.querySelector('#card'), { format: 'png' });
const url = URL.createObjectURL(blob);

const a = document.createElement('a');
a.href = url;
a.download = 'card.png';
a.click();

URL.revokeObjectURL(url);

Pattern 3 — Upload the PNG to a server

Capture the element to a Blob, wrap it in FormData, and POST it to your endpoint:

const blob = await snapdom.toBlob(document.querySelector('#card'), { format: 'png' });

const form = new FormData();
form.append('file', blob, 'card.png');

const response = await fetch('/api/upload', {
  method: 'POST',
  body: form,
});

const { url } = await response.json();
console.log('Uploaded to', url);

This is the same pattern you'd use to generate dynamic og:image share cards — capture the rendered card client-side, upload to a CDN, return the URL.

Try the three patterns live

Same element, three buttons — append the PNG, download it, or produce the upload-ready Blob:

HTML PNG

Gradients, borders & shadows

Rounded corners, a dashed border, a gradient — ready to capture together.

⚡ Even this shadow
The result will appear here.

Bonus — Get a Base64 / data URL

If you specifically need a base64 string (e.g. to email or embed inline), call toPng and read the src of the returned image:

const img = await snapdom.toPng(document.querySelector('#card'));
const dataUrl = img.src; // "data:image/png;base64,iVBORw0KGgo…"

High-DPI / retina output

SnapDOM picks up the device's devicePixelRatio automatically through the dpr option, so retina screens already get sharp output without configuration. Override it with dpr when you want a fixed pixel density (e.g. exporting a 2× asset on a non-retina machine):

const img = await snapdom.toPng(el, { dpr: 2 });

scale multiplies the captured size when no explicit width or height is set. Use scale when you want a larger image; use dpr when you want the same logical size at higher pixel density. They can be combined:

const img = await snapdom.toPng(el, {
  dpr: 2,            // retina pixel density
  scale: 1.5,        // zoom 1.5×
  backgroundColor: '#ffffff',
});

Frequently asked questions

Can I convert HTML to PNG without a server?

Yes. SnapDOM runs in the browser and does not need a screenshot server. Its SVG foreignObject pipeline uses the browser's renderer; fonts and images may still require network requests.

What if I need JPG or WebP instead of PNG?

Use snapdom.toJpg(el, { quality: 0.9 }) or snapdom.toWebp(el, { quality: 0.9 }). The API surface is identical, only the output format changes.

How do I render custom fonts correctly?

SnapDOM v3.x.x defaults to embedFonts: 'auto', which embeds used web fonts when their files are accessible. Use localFonts or excludeFonts when you need more control.

Can I exclude some elements from the capture?

Yes. Pass { exclude: ['.skip-me'] } with a list of CSS selectors, or { exclude: node => … } for a predicate that returns true for nodes to omit.

What about converting HTML to PDF?

Use the MIT pdf plugin. Its toPdf() method returns a PDF Blob with selectable text, pagination and links. The plugin is available on npm in @zumer/snapdom-plugins 4.x; see the PDF reference for installation and examples.

Does it handle Shadow DOM and Web Components?

Yes. SnapDOM walks open Shadow DOM trees during cloning, and preserves their rendered styles subject to the same resource and browser limits as other captures.

Try the live demo

Capture any element on snapdom.dev to see the output before installing.

Open the demo Installation