Copy HTML content with navigator clipboard

We have often seen “Copy” buttons for plain text. Thanks to navigator.clipboard‘s API, we can also programatically copy and paste HTML content.

The copy code

Let’s imagine we have a bit of HTML content that includes links and other basic HTML code. We want our end users to be able to copy it exactly as it is and use it elsewhere.

For this exercise, we will be working with a simple HTML page that looks like the screenshot below:

A screenshot of the example webpage with a section containing HTML and a 'Copy to Clipboard' button

The main elements are a section with id=”copy-content” that contains the HTML to be copied (the blue text in the screenshot above), and a “Copy to clipboard” button, with id=”copy-button”.

The HTML and CSS code for the screenshot can be found in this gist.

Initially, the javascript that makes it all happen looks like this:

const copyButton = document.getElementById("copy-button");
copyButton.addEventListener("click", copyContent);

function copyContent() {
  const content = document.getElementById("copy-content").innerHTML;
  addHtmlToClipboard(content);
}

function addHtmlToClipboard(content) {
  const type = "text/html";
  const blob = new Blob([content], { type });
  const data = [new ClipboardItem({ [type]: blob })];

  navigator.clipboard.write(data).then(
    () => {
      console.log("copied to clipboard");
    },
    () => {
      console.log("failed to copy to clipboard");
    },
  );
}

First, we add a “click” event to the “Copy to clipboard” button so that, when the button is clicked, the copyContent function is executed.

This copyContent function, gets the HTML content we want to copy and passes it to the addHtmlToClipboard function.

The addHtmlToClipboard function then takes this content, converts it into an HTML Blob and creates a new ClipboardItem with it. This is then writen into the navigator clipboard API using navigator.clipboard.write.

If the clipboard API succedes, the content is ready to be pasted elsewhere. For example, in a Word document or an email.

Note the inline CSS it is also copied but not that which is in a separate file.

Firefox gotcha

Unfortunately the ClipboardItem funtionality is not yet supported by all browsers, notably Firefox.

As a compromise, we can change the code so that at least the text content is copied to clipboard if the full functionality cannot be used. Here is the updated code:

const copyButton = document.getElementById("copy-button");
copyButton.addEventListener("click", copyContent);

function copyContent() {
  const content = document.getElementById("copy-content").innerHTML;
  
  if(typeof ClipboardItem === "function") {
    addHtmlToClipboard(content);
  } else {
    const textContent = sanitize(content);
    addTextToClipboard(textContent);
  }
}

function addHtmlToClipboard(content) {
  const type = "text/html";
  const blob = new Blob([content], { type });
  const data = [new ClipboardItem({ [type]: blob })];

  navigator.clipboard.write(data).then(
    () => {
      console.log("copied html to clipboard");
    },
    () => {
      console.log("failed to copy html to clipboard");
    },
  );
}

// removes all HTML tags and empty spaces at either end
function sanitize(content) {
  const pattern = /<\/?[\w ="'-:;\/\.]+>/g;

  return content.replaceAll(pattern, "").trim();
}

function addTextToClipboard(text) {
  navigator.clipboard.writeText(text).then(
    () => {
      console.log("copied text to clipboard");
    },
    () => {
      console.log("failed to copy text to clipboard");
    },
  );
}

So what has changed? First of all the copyContent function, after getting the content to be copied, checks whether the ClipboardItem functionality is available.

If it is, the addHtmlToClipboard function is run just as before. If it isn’t available, the new addTextToClipboard function is run instead.

This new addTextToClipboard takes the content to be copied, removes all traces of HTML code from it (via the sanitize function) and then writes it as text into the clipboard using navigator.clipboard.writeText.

You can see the difference in this video recording. The browser on the left is Chrome and the browser on the right is Firefox:

Useful resources

You can find the full code in the gist created for this blog post, including the HTML, CSS and javascript files.

A separate article will be written in the future with the code to also paste HTML content programatically.


Posted

in

by