Unblocking Clipboard Access

For the past few years we have only been able to manipulate the clipboard using Document. execCommand. However, this manipulation of the clipboard is synchronous and can only read and write to the DOM.

Chrome 66 now supports the new Async Clipboard API as a replacement for execCommand.

The new Async Clipboard API can also use Promises to simplify Clipboard events and use them with the Drag-&-Drop API.

Demo video: zhuanlan.zhihu.com/p/34698155

Copy: Writes text to the clipboard

WriteText () writes text to the clipboard. WriteText () is asynchronous and returns a Promise:

navigator.clipboard.writeText('Text to copy')
  .then((a)= > {
    console.log('Text has been successfully copied to clipboard');
  })
  .catch(err= > {
    // This can happen if the user denies clipboard permissions:
    // If the user is not authorized, an exception is thrown
    console.error('Cannot copy this text:', err);
  });
Copy the code

You can also use async and await of asynchronous functions:

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); }}Copy the code

Paste: Reads text from the clipboard

As with copying, text can be read from the clipboard by calling readText(), which also returns a Promise:

navigator.clipboard.readText()
  .then(text= > {
    console.log('Pasted content: ', text);
  })
  .catch(err= > {
    console.error('Failed to read clipboard contents: ', err);
  });
Copy the code

For consistency, here is the equivalent asynchronous function:

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); }}Copy the code

Handling paste Events

There are plans for new events that detect clipboard changes, but for now it’s best to use the “Paste” event. It is well suited to the new asynchronous method for reading clipboard text:

document.addEventListener('paste', event => {
  event.preventDefault();
  navigator.clipboard.readText().then(text= > {
    console.log('Pasted text: ', text);
  });
});
Copy the code

Security and permissions

Clipboard access has always posed security problems for browsers. Without proper permissions, pages can quietly copy all malicious content to the user’s clipboard, with disastrous results when pasted. Imagine a web page that silently copies the RM-RF/or unzips the bomb image to the clipboard.

Making it more cumbersome for web pages to read the clipboard without restriction. Users often copy sensitive information, such as passwords and personal details, to the clipboard, which can then be read through any page without the user noticing.

As with many new apis, navigator.clipboard only supports pages served over HTTPS. To prevent abuse, clipboard access is only allowed when the page is in the active TAB. Pages in the active TAB can be written to the clipboard without requesting permission, but reading from the clipboard always requires permission.

To make it easier, two new Permissions for copy and paste have been added to the Permissions API. Clipboard-write permission is automatically granted to a page when it is in the active TAB. When you read data from the clipboard, you must ask for clipboard-read permission.

{ name: 'clipboard-read' }
{ name: 'clipboard-write' }
Copy the code

As with anything else using the permissions API, you can check if your application has permissions to interact with the clipboard:

navigator.permissions.query({
  name: 'clipboard-read'
}).then(permissionStatus= > {
  // permissionStatus.state values are 'granted', 'denied', 'prompt':
  console.log(permissionStatus.state);

  // Listen for permission status change events
  permissionStatus.onchange = (a)= > {
    console.log(permissionStatus.state);
  };
});
Copy the code

Here’s where the “asynchronous” part of the Clipboard API really comes in handy: Attempting to read or write clipboard data will automatically prompt the user for permission (if not already granted). Because the API is based on promises, promises are rejected if the user rejects clipboard permissions, so the page can respond appropriately.

Because Chrome only allows clipboard access if the page is currently active, some of the examples here don’t work correctly if you paste them directly into DevTools, where DevTools itself is active (the page is not). Here’s a trick: we need to use setTimeout to delay the clipboard access and then quickly click inside the page to get focus before calling the function:

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

review

Prior to the introduction of the asynchronous Clipboard API, we mixed different copy and paste implementations in the Web browser.

Document. execCommand(‘copy’) can be used in most browsers and trigger the browser’s own copy and paste of Document. execCommand(‘paste’). If the text to be copied is a string that does not exist in the DOM, we must insert it into the DOM and select it:

button.addEventListener('click', e => {
  const input = document.createElement('input');
  document.body.appendChild(input);
  input.value = text;
  input.focus();
  input.select();
  const result = document.execCommand('copy');
  if (result === 'unsuccessful') {
    console.error('Failed to copy text.'); }})Copy the code

Again, here’s how you handle pasted content in browsers that don’t support the new Async Clipboard API:

document.addEventListener('paste', e => {
  const text = e.clipboardData.getData('text/plain');
  console.log('Got pasted text: ', text);
})
Copy the code

In Internet Explorer, we can also access the clipboard through window.clipboardData. If access is made within a user gesture (such as a click event) – part of the permission is requested in a responsible manner – the permission prompt is not displayed.

Detection and rollback

It’s a good idea to use feature detection to take advantage of the asynchronous clipboard while supporting all browsers. You can detect support for the Async Clipboard API by checking navigator. Clipboard:

document.addEventListener('paste'.async e => {
  let text;
  if (navigator.clipboard) {
    text = await navigator.clipboard.readText()
  }
  else {
    text = e.clipboardData.getData('text/plain');
  }
  console.log('Got pasted text: ', text);
});
Copy the code

What’s next for the asynchronous Clipboard API?

As you may have noticed, this article only covers the text portion of navigator.clipboard. There are more generic read() and write() methods in the specification, but these introduce additional implementation complexity and security issues (remember those image bombs?). . Chrome is currently rolling out a simpler text section of the API.

For more information

  • Chrome Platform Status
  • Code sample
  • API
  • explain
  • Implementation plan
  • discuss