If you want to take a screenshot of part or all of your web page using JavaScript, you might find yourself stuck. Creating an image from an HTML element can seem like a challenge, as there's no direct way to do it in JavaScript.

Thankfully, this isn't an impossible task and is, in fact, quite easy with the proper tools. Using the html-to-image library, making images of DOM nodes is as simple as a single function call.

How Does html-to-image Work?

The html-to-image library produces an image in the form of a base64 data URL. It supports several output formats, including PNG, JPG, and SVG. To perform this conversion, the library uses this algorithm:

  1. Create a clone of the target HTML element, its children, and any attached pseudo-elements.
  2. Copy the styling for all cloned elements and embed the styling inline.
  3. Embed the relevant web fonts, if there are any.
  4. Embed any images present.
  5. Convert the cloned node into XML, and then SVG.
  6. Use the SVG to create a Data URL.

Caveats and Limitations

Even though html-to-image is a great library, it's not perfect. It has a few caveats, namely:

  • The library will not work in Internet Explorer or Safari.
  • If the HTML you try to convert includes a tainted canvas element, the library will fail. As MDN explains, including non-CORS-approved data in your canvas element will taint it.
  • Because browsers place limits on the maximum size of a data URL, there are limits on the size of the HTML the library can convert.

Using the Library

To try the library out, the first thing you need to do is create a project directory on your local machine. Next, install html-to-image in that directory using the npm package manager. Here's the terminal command to install it:

        npm install --save html-to-image
    

You should also install a JavaScript bundler, to make it a little easier to use the library. The esbuild bundler can help package node modules into web-compatible scripts.

        npm install esbuild
    

That's all you need to install. Next, create a file called index.html in your directory, and serve it with a web server of your choice. Put the following code in index.html:

        <!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
    .colorful-div {
        padding: 3rem;
        color: white;
        background-image: linear-gradient(to right, yellow, rebeccapurple);
        border: 1px solid black;
        margin: 1rem auto;
        font-size: 3rem;
        font-family: cursive;
    }
    </style>
</head>
<body>

<div class="colorful-div">
    I'm going to be in a screenshot!
</div>

<div class="long-text">
    I'm an example of a sufficiently verbose paragraph that
    illustrates that taking screenshots in JavaScript is
    really very easy, for the following reasons:
    <ul>
        <li>Reason 1</li>
        <li>Reason 2</li>
        <li>Reason 2</li>
    </ul>
</div>
 
<script src="out.js"></script>
</body>
</html>

This code creates two elements on the page: a div with a gradient background, and some text and an unordered list inside another div. Next, you'll write the JavaScript to convert these elements to images. Put the following code in a new file called script.js:

        import * as htmlToImage from "html-to-image";
 
const elems = ['.colorful-div', '.long-text']
 
elems.forEach((elem, ind) => {
    const node = document.querySelector(elem)
 
    htmlToImage.toPng(node)
        .then(function (dataUrl) {
            let img = new Image();
            img.src = dataUrl;
            document.body.appendChild(img);
        })
        .catch(function (error) {
            console.error('oops, something went wrong!');
            console.log(error)
        });
})

This code does a few things:

  • Imports the html-to-image library.
  • Creates an array made of CSS selectors targeting the two elements.
  • Creates a PNG image in the form of a data URL from each element of the array.
  • Creates an img tag and sets its src attribute to the data URL, creating image copies of the two elements.

Now use esbuild to generate the bundled file (out.js) that index.html references by running the following in your terminal:

         ./node_modules/.bin/esbuild script.js --bundle --outfile=out.js

At this point, here's what index.html should look like in your browser:

a demo page for html-to-image

Even though the copies look exactly the same as the originals, they are actually image elements. You can confirm this by opening your dev tools and inspecting them.

This library also works with JavaScript frameworks. The html-to-image documentation contains instructions on how to generate other image formats. It also includes an example showing how to use the library with React.

Taking Screenshots With JavaScript Is Easy

There's no native JavaScript method for creating images from HTML elements, or taking screenshots of the DOM. However, with the help of libraries and services like html-to-image, it becomes an easy task.

There are other ways of achieving similar results, such as the wkhtmltoimage library. You can use this open-source tool to take screenshots of a complete web page.