html-to-image: Rendering DOM Nodes to PNG, JPEG and SVG in the Browser
✂️ Generates an image from a DOM node using HTML5 canvas and SVG.
At a glance
- What is it?
- A TypeScript fork of dom-to-image that turns a live DOM node into a data URL, blob or canvas through an SVG foreignObject. Useful for client-side export buttons, awkward when the DOM is not what the user sees.
- Who is it for?
- Adopt html-to-image when the thing you want to capture is a DOM subtree you control and the export happens in the browser, since toPng and toSvg return promises over data URLs and the filter and cacheBust options cover the common obstacles. Do not adopt it for whole-page screenshots, for pages you do not control, or where the source of truth is not the DOM.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 129 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 3, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What html-to-image is for, and who actually needs it
The problem is narrow and specific: you have a piece of interface rendered as DOM, and you need a file that looks like it. A share card, an invoice preview, a chart with a legend, a certificate with the user's name typed into it. The user is looking at the real thing, and the export has to match what they see without a server round trip.
The README states the project "Generates an image from a DOM node using HTML5 canvas and SVG" and describes itself as a "Fork from dom-to-image with more maintainable code and some new features." That fork lineage matters more than the feature list. dom-to-image was widely used and lightly maintained; this project keeps the same idea and the same public shape (top-level functions returning promises) and adds options that the original did not have.
It is aimed at front-end engineers working in JavaScript or TypeScript who already have the node in the page. If your export pipeline starts from a template string on a server, or from a headless browser you control, this is not the tool for that job.
The SVG foreignObject trick behind toPng and toSvg
Nothing here rasterizes the DOM directly. The mechanism, as the README and the function names imply, is a two-step conversion: serialize the node into an SVG document, wrap the markup in a foreignObject element, then draw that SVG into a canvas and read the pixels back out.
That explains the exported surface. toSvg stops after the first step and hands you an SVG data URL. toPng, toJpeg, toBlob, toCanvas and toPixelData continue through the canvas. toPixelData returns a Uint8Array where, per the README, "every 4 array elements representing the RGBA data of a pixel", with the sample loop indexing by node.scrollHeight and node.scrollWidth.
It also explains the failure modes you will meet. Anything the SVG serializer cannot express has to be inlined first, which is why cache busting and query-param handling exist as options at all. The rendering is a snapshot of markup and computed styles, not a recording of the compositor, so effects that only exist at paint time do not survive.
Installing html-to-image from npm and capturing your first node
The README gives exactly one install command, and it is a plain npm install with no peer dependencies to satisfy:
npm install --save html-to-imageAfter that, import the function you need. The README shows both module styles, and notes that all top-level functions accept a DOM node plus rendering options and return a promise fulfilled with the corresponding data URL:
import { toPng, toJpeg, toBlob, toPixelData, toSvg } from 'html-to-image';The smallest real use is to grab a node by id and hand it to toPng. The README's first example appends the result to the page so you can see it immediately:
const node = document.getElementById('my-node');
htmlToImage
.toPng(node)
.then((dataUrl) => {
const img = new Image();
img.src = dataUrl;
document.body.appendChild(img);
})
.catch((err) => {
console.error('oops, something went wrong!', err);
});If the capture comes out empty or stale, the README's React example is the pattern to copy: it passes cacheBust: true alongside the node reference, which appends the current time as a query string to URL requests.
toPng(ref.current, { cacheBust: true })For a JPEG export, pass quality as a number between 0 and 1. The README uses 0.95 and notes the default is 1.0.
filter, style and the options that decide what gets captured
The option with the most leverage over output is filter. It takes a function of the DOM node and returns true when the node should be included. The README is explicit about the consequence: "Excluding node means excluding it's children as well." It also notes the filter is "Not called on the root node", so you cannot use it to reject the node you passed in.
The README's own example excludes by class name, which is the practical way to drop a toolbar or a watermark before export:
exclusionClasses = ['remove-me', 'secret-div'];
return !exclusionClasses.some((classname) => node.classList?.contains(classname));Two pairs of size options are easy to confuse. width and height are "applied to node before rendering" in pixels. canvasWidth and canvasHeight instead "scale the canva's size including the elements inside to a given width and height", which is the pair you want when the output resolution should differ from the on-screen size. The style option copies JavaScript-named CSS properties onto the node before rendering, so the README points at the MDN CSS Properties Reference for the naming.
includeQueryParams defaults to false, and the README says a falsy value "will exclude query params from the provided URL". That is a cache-key decision, not a visual one, and it can bite when two different URLs differ only by query string.
Where html-to-image breaks: cross-origin assets and effects it cannot see
The single most common failure is a tainted canvas. Because the pipeline draws into a canvas and then reads it back, any image or font that the browser will not let you read from will stop the export. The README does not document a workaround beyond cache busting and the query-param option, so in practice you either serve the assets from the same origin with permissive CORS headers or you accept that the capture fails. This is not a bug in the library; it is the browser's security model applied to the technique the library uses.
The second limitation is scope. The README describes a DOM node, singular. There is no whole-page capture mode and no scrolling stitch. If you need the entire viewport including fixed headers and whatever the browser chrome is doing, the technique is the wrong shape for the problem.
The third is fidelity of effects that never enter the DOM tree. The library serializes markup and computed style; it does not replay animations, video frames, canvas contents that are themselves tainted, or anything drawn by the compositor outside the node's subtree. The README is silent on how each of these is handled, which is itself the answer: do not assume they are.
The project also carries maintenance risk that is visible in the release history. The last push to the repository was on 2026-05-28, but the most recent release listed is v1.11.13 from 2025-02-14, and the one before that, v1.11.11, dates to 2023-02-01. A long gap between releases is not proof of abandonment, and the repository is not archived, but it does mean the version you install may not reflect the current state of master.
html-to-image vs html2canvas, and when to use neither
The obvious comparison is html2canvas, and the difference in approach is the whole story. html2canvas reimplements rendering: it walks the DOM, computes styles, and paints an approximation onto a canvas itself. html-to-image delegates to the browser by way of SVG foreignObject, so the browser renders the markup and the library only orchestrates the serialization and the canvas read-back.
The practical consequences follow. Delegating means less code that can drift from real rendering, but it also means you inherit every restriction the browser places on foreignObject, and support for that element varies by engine. Reimplementing means html2canvas can sometimes handle cases foreignObject cannot, at the cost of a renderer that has to be kept in sync with CSS by hand. Neither is strictly better; they fail in different places.
There is also a category of problem where both are the wrong tool. If the page is not yours, if the export has to run without a browser, or if the source of truth is a data structure rather than the DOM, then the right move is to render the image from that data directly (server-side with a canvas or SVG library, or with a headless browser you control) instead of screenshotting a page you had to build first.
Licence, upgrade cost, and what the repository tells you about maintenance
The licence is MIT, per both the repository metadata and the LICENSE file. MIT is permissive: it allows commercial and closed-source use, modification and redistribution, provided the copyright notice and permission notice are preserved. That is a description of the licence text, not legal advice; if your organisation has a policy review for third-party dependencies, MIT is usually the easy case, but the review is still yours to run.
The upgrade cost is low by construction. The package publishes dist, es, lib and src, with main, module, unpkg and types fields in package.json, so it works as CommonJS, as ESM, as a UMD script in the browser and as TypeScript without a separate types package. Nothing in the README describes a breaking change between the listed releases, and the public API is a small set of functions plus an options object.
The maintenance picture is mixed and worth stating plainly. The repository is not archived and the last push was on 2026-05-28, so work is happening. But the release cadence has been uneven: v1.11.11 in February 2023, then v1.11.12 and v1.11.13 within two days of each other in February 2025. If you pin a version, pin deliberately, and check the CHANGELOG before moving.
Editorial conclusion
Adopt html-to-image when the thing you want to capture is a DOM subtree you control and the export happens in the browser, since toPng and toSvg return promises over data URLs and the filter and cacheBust options cover the common obstacles. Do not adopt it for whole-page screenshots, for pages you do not control, or where the source of truth is not the DOM. Before committing, verify three things in your own page: that every image and font in the captured subtree is same-origin or CORS-enabled, that the CSS your node depends on is inline or in a stylesheet the browser can read, and that the renderer you target supports SVG foreignObject, because the README does not document a fallback for browsers that do not.
Frequently asked questions
How can I convert HTML to an image?
With html-to-image, pass a DOM node to one of the top-level functions such as toPng, and the returned promise resolves to a base64-encoded data URL you can put into an Image element or a download link. The README's first example does exactly that with document.getElementById('my-node').
How do I use html-to-image?
Install it with npm install --save html-to-image, import the function you need, and call it with a node plus optional rendering options. Every top-level function accepts a DOM node and options and returns a promise fulfilled with the corresponding data URL.
How do I convert HTML to an image with html-to-image?
Import toPng, toJpeg, toBlob or toSvg from html-to-image, pass the target node, and handle the promise. For a JPEG you can also pass quality as a number between 0 and 1, which the README shows as 0.95 against a default of 1.0.
What is html-to-image?
It is a TypeScript library that generates an image from a DOM node using HTML5 canvas and SVG, described in the README as a fork of dom-to-image with more maintainable code and some new features. It is distributed on npm as html-to-image under the MIT licence.
What is a html-to-image alternative?
html2canvas is the closest alternative and takes the opposite approach: it reimplements rendering by walking the DOM and painting onto a canvas, rather than serializing into an SVG foreignObject and letting the browser render it. The two fail in different places, so the choice depends on which restrictions you can live with.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/bubkoo-html-to-image)