Clipboard Operations Clipboard API Tutorial

Clipboard Operations Clipboard API Tutorial

Browsers allow JavaScript scripts to read and write to the clipboard, automatically copying or pasting content.

In general, scripts should not modify the user’s clipboard, lest it not meet the user’s expectations. However, sometimes this can really bring convenience, such as the “one-click copy” function, the user clicks a button, and the specified content is automatically entered into the clipboard.

Currently, there are three ways to implement clipboard operations.

  • Document.execCommand() method
  • Asynchronous Clipboard API
  • copy event and paste event

This article introduces these three methods one by one.

Document.execCommand() method

Document.execCommand() is the traditional method of operating the clipboard, supported by various browsers.

It supports three operations of copy, cut and paste.

document.execCommand('copy')
document.execCommand('cut')
document.execCommand('paste')

Copy operation

When copying, select the text first, then call document.execCommand('copy'), the selected text will enter the clipboard.

const inputElement = document.querySelector('#input');
inputElement.select();
document.execCommand('copy');

inputElementIn the above example, the script first selects the text (inputElement.select()) in the input box , and then document.execCommand('copy') copies it to the clipboard.

Note that the copy operation is best placed in the event listener function, triggered by the user (for example, the user clicks a button). Some browsers may report an error if the script executes autonomously.

paste operation

When pasting, the call document.execCommand('paste') will output the contents of the clipboard to the current focus element.

const pasteText = document.querySelector('#output');
pasteText.focus();
document.execCommand('paste');

shortcoming

Document.execCommand() Although the method is convenient, it has some disadvantages.

First, it can only copy the selected content to the clipboard, and cannot write arbitrary content to the clipboard.

Second, it’s a synchronous operation, and if you copy/paste a lot of data, the page will stutter. Some browsers will also pop up a prompt box to ask the user for permission, and the page will become unresponsive before the user makes a choice.

To solve these problems, browser vendors have proposed asynchronous Clipboard APIs.

Asynchronous Clipboard API

The Clipboard API is the next generation of clipboard manipulation methods that are document.execCommand() more powerful and reasonable than traditional methods.

All its operations are asynchronous, return Promise objects, and will not cause page freezes. Moreover, it can put arbitrary content (such as pictures) into the clipboard.

navigator.clipboard The property returns the Clipboard object through which all operations are performed.

const clipboardObj = navigator.clipboard;

If the navigator.clipboard property returns undefined, it means that the current browser does not support this API.

Since users may put sensitive data (such as passwords) on the clipboard, allowing scripts to read arbitrarily will create security risks, so this API has more security restrictions.

First of all, the Chrome browser stipulates that only pages of the HTTPS protocol can use this API. However, the development environment (localhost) allows the use of non-encrypted protocols.

Second, the invocation requires explicit permission from the user. The specific implementation of permissions uses the Permissions API, and there are two permissions related to the clipboard: clipboard-write and clipboard-read. “Write permission” is automatically granted to the script, while “read permission” must be given explicitly by the user. That is, writing to the clipboard, the script can be done automatically, but when reading the clipboard, the browser will pop up a dialog box asking the user to agree to read.

Also, note that the script always reads the clipboard of the current page. One problem this brings is that if you paste the relevant code into the developer tool and run it directly, an error may be reported, because the current page is the window of the developer tool, not a web page.

(async () => {
  const text = await navigator.clipboard.readText();
  console.log(text);
})();

If you paste the above code into the developer tool and run it, an error will be reported. Because when the code is running, the developer tool window is the current page, and this page does not have the DOM interface that the Clipboard API depends on. One solution is to put the relevant code setTimeout() in it and delay it, and quickly click the browser’s page window before calling the function to turn it into the current page.

setTimeout(async () => {
  const text = await navigator.clipboard.readText();
  console.log(text);
}, 2000);

After the above code is pasted into the developer tool to run, quickly click the page window of the web page to make it the current page, so that no error will be reported.

Clipboard object

The Clipboard object provides four methods for reading and writing to the clipboard. They are all asynchronous methods that return Promise objects.

Clipboard.readText()

Clipboard.readText() The method is used to copy the text data in the clipboard.

document.body.addEventListener(
  'click',
  async (e) => {
    const text = await navigator.clipboard.readText();
    console.log(text);
  }
)

In the above example, when the user clicks on the page, the text in the clipboard is output. Note that the browser will then pop up a dialog asking the user for permission to the script to read the clipboard.

If the user disagrees, the script will report an error. At this time, you can use the try...catch structure to handle the error.

async function getClipboardContents() {
  try {
    const text = await navigator.clipboard.readText();
    console.log('Pasted content: ', text);
  } catch (err) {
    console.error('Failed to read clipboard contents: ', err);
  }
}

Clipboard.read()

Clipboard.read() The method is used to copy the data in the clipboard, which can be text data or binary data (such as pictures). This method requires explicit permission from the user.

This method returns a Promise object. Once the state of the object becomes resolved, you can obtain an array, each of which is an instance of a ClipboardItem object.


async function getClipboardContents() {
  try {
    const clipboardItems = await navigator.clipboard.read();
    for (const clipboardItem of clipboardItems) {
      for (const type of clipboardItem.types) {
        const blob = await clipboardItem.getType(type);
        console.log(URL.createObjectURL(blob));
      }
    }
  } catch (err) {
    console.error(err.name, err.message);
  }
}

A ClipboardItem object represents a single clip item, each of which has ClipboardItem.types properties and ClipboardItem.getType() methods.

ClipboardItem.types The property returns an array whose members are the available MIME types for the clipping item. For example, a clipping item can be pasted in HTML format or in plain text format, then it has two MIME types (text/html and text/plain).

ClipboardItem.getType(type)The method is used to read the data of the clipped item and returns a Promise object. This method accepts the MIME type of the clipping item as a parameter, and returns the data of this type. This parameter is required, otherwise an error will be reported.

Clipboard.writeText()

Clipboard.writeText() method is used to write the text content to the clipboard.


document.body.addEventListener(
  'click',
  async (e) => {
    await navigator.clipboard.writeText('Yo')
  }
)

The above example is that after the user clicks on the web page, the script writes text data to the clipboard.

This method does not require user permission, but it is best to put try...catch it in it to prevent errors.

async function copyPageUrl() {
  try {
    await navigator.clipboard.writeText(location.href);
    console.log('Page URL copied to clipboard');
  } catch (err) {
    console.error('Failed to copy: ', err);
  }
}

Clipboard.write()

Clipboard.write() Methods are used to write arbitrary data to the clipboard, either text data or binary data.

This method accepts a ClipboardItem instance as a parameter representing the data written to the clipboard.

try {
  const imgURL = 'https://dummyimage.com/300.png';
  const data = await fetch(imgURL);
  const blob = await data.blob();
  await navigator.clipboard.write([
    new ClipboardItem({
      [blob.type]: blob
    })
  ]);
  console.log('Image copied.');
} catch (err) {
  console.error(err.name, err.message);
}

In the above example, the script writes an image to the clipboard. Note that the Chrome browser currently only supports writing images in PNG format.

ClipboardItem() It is a constructor provided natively by the browser to generate ClipboardItem an instance. It accepts an object as a parameter, the key name of the object is the MIME type of the data, and the key value is the data itself.

The following example is to write the values ​​of the same clip item in multiple formats into the clipboard, one is text data and the other is binary data for pasting in different occasions.


function copy() {
  const image = await fetch('kitten.png');
  const text = new Blob(['Cute sleeping kitten'], {type: 'text/plain'});
  const item = new ClipboardItem({
    'text/plain': text,
    'image/png': image
  });
  await navigator.clipboard.write([item]);
}

copy event, cut event

The event fires when the user puts data into the clipboard copy.

The example below is text that the user puts into the clipboard, converted to uppercase.


const source = document.querySelector('.source');

source.addEventListener('copy', (event) => {
  const selection = document.getSelection();
  event.clipboardData.setData('text/plain', selection.toString().toUpperCase());
  event.preventDefault();
});

In the above example, the event object’s clipboardData property contains the clipboard data. It is an object with the following properties and methods.

Event.clipboardData.setData(type, data)
Event.clipboardData.getData(type)
Event.clipboardData.clearData([type])
Event.clipboardData.items

The following example is to intercept the user’s copy operation and put the specified content into the clipboard.

const clipboardItems = [];

document.addEventListener('copy', async (e) => {
  e.preventDefault();
  try {
    let clipboardItems = [];
    for (const item of e.clipboardData.items) {
      if (!item.type.startsWith('image/')) {
        continue;
      }
      clipboardItems.push(
        new ClipboardItem({
          [item.type]: item,
        })
      );
      await navigator.clipboard.write(clipboardItems);
      console.log('Image copied.');
    }
  } catch (err) {
    console.error(err.name, err.message);
  }
});

In the above example, e.preventDefault() the default operation of the clipboard is canceled by using , and then the script takes over the copy operation.

cutThe event is triggered when the user performs the cut operation, and its processing copy is exactly the same as the event, and it also Event.clipboardData gets the cut data from the attribute.

paste event

When the user uses the clipboard data and performs a paste operation, an event will be triggered paste.

The following example is to intercept the paste operation, and the script will take out the data in the clipboard.

document.addEventListener('paste', async (e) => {
  e.preventDefault();
  const text = await navigator.clipboard.readText();
  console.log('Pasted text: ', text);
});

Reference link