Skip to main content




More secure and unlocked clipboard access for text and images


Updated

En los últimos años, los browsers han utilizado
document.execCommand ()

for interactions with the clipboard. Although widely supported, this cut and paste method came at a cost: clipboard access was synchronous and could only read and write to the DOM.

Eso está bien para pequeños fragmentos de texto, pero hay muchos casos en los que bloquear la página para la transferencia del portapapeles es una mala experiencia. Es viable que se necesite una desinfección o decodificación de imágenes que requiera mucho tiempo antes de que el contents se pueda pegar de forma segura. Es viable que el browser necesite cargar o incorporar recursos vinculados desde un documento pegado. Eso bloquearía la página mientras espera en el disco o la red. Imagine agregar permisos a la mezcla, requiriendo que el navegador bloquee la página mientras solicita acceso al portapapeles. A la vez, los permisos establecidos alrededor
document.execCommand () for clipboard interaction are loosely defined and vary between browsers.

the
Async Clipboard API
addresses these issues by providing a well-defined permissions model that doesn't lock the page. Recently announced safari support for it in version 13.1. Con eso, los principales navegadores disponen un nivel básico de soporte. A la hora de escribir estas líneas, Firefox solo admite texto; y el soporte de imágenes está limitado a PNG en algunos navegadores. Si está interesado en usar la API,
consult a browser support table
before continuing.

East post explica cómo escribir texto e imágenes y cómo leerlos desde el portapapeles. Este post no cubre Feature policy for the clipboard which landed on Chrome 85.

The Async Clipboard API is limited to handling text and images. Chrome 84 introduces an experimental feature that allows the clipboard to handle any arbitrary data type.

Copy: write data to clipboard

writeText ()

To copy text to the clipboard callout writeText (). Since this API is asynchronous, the writeText () The function returns a Promise that is resolved or rejected depending on whether the passed text is copied correctly:

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);
}
}

to write()

Truly, writeText () it is just a convenience method for the generic write ()
method, which also enables you to copy images to the clipboard. I like it writeText (), is asynchronous and returns a Promise.

To write an image to the clipboard, you require the image as
blob. Una forma de hacer esto es solicitando la imagen de un server using fetch (), then calling
blob () in solution.

Requesting an image from the server may not be desirable or feasible for a range of reasons. Luckily, you can also draw the image on a canvas and call the canvas'
toBlob ()

method.

Then pass an array of ClipboardItem objects as a parameter for the write ()
method. Today, you can only pass one image at a time, but we hope to add support for multiple images in the future. ClipboardItem toma un objeto con el tipo Mime de la imagen como clave y el blob como valor. Para objetos Blob obtenidos de fetch () or canvas.toBlob (), the blob.type The property automatically contains the correct MIME type for an image.

try {
const imgURL = '/images/generic/file.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.yam, err.message);
}

The event de copia

En el caso de que un Username inicie una copia del portapapeles, se le proporcionarán datos no textuales como un blob. los
copy event
includes a clipboardData with items that are already in the correct format, eliminating the need to manually create a Blob. Call preventDefault () To bypass the default behavior in favor of your own logic, then copy the content to the clipboard. What is not covered in this example is how to fall back to older APIs when the Clipboard API is not supported. I'll cover that in Feature Detection, later in this post.

document.addEventListener('copy', async (and) => {
and.preventDefault();
try {
let clipboardItems = [];
for (const item of and.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.yam, err.message);
}
});

Paste: read data from clipboard

Read the text ()

To read text from the clipboard, call navigator.clipboard.readText () and wait for the returned Promise to be resolved:

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);
}
}

read()

the navigator.clipboard.read () Additionally, the method is asynchronous and returns a Promise. To read an image from the clipboard, get a list of
ClipboardItem

objects, then iterate over them.

Every ClipboardItem can contain its content in different types, so you will have to iterate over the list of types, again using a for ... of ribbon. For each type, call getType () with the current type as an argument to get the respective Blob. As before, this code is not linked to images and will work with other future file types.

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.yam, err.message);
}
}

The paste event

As previously noted, there are plans to introduce events to work with the Clipboard API, but for now you can use the existing one paste event. Works great with new asynchronous methods for reading clipboard text. As with the copy event, don't forget to call preventDefault ().

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

As with the copy event, fall back to older APIs when Clipboard API is not supported will be covered in Function Detection.

Handling various types of files

La mayoría de las implementaciones colocan diversos formatos de datos en el portapapeles para una sola operación de corte o copia. Hay dos razones para ello: como desarrollador de aplicaciones, no tiene forma de conocer las capacidades de la aplicación en la que un usuario desea copiar texto o imágenes, y muchas aplicaciones admiten pegar datos estructurados como texto sin formato. Esto se presenta a los usuarios con un Edit menu item with a name like Paste and match style or Paste without formatting.

The following example shows how to do this. This example uses fetch () to get image data, but it could also come from a

or the native filesystem API.

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]);
}

Security and permissions

El acceso al portapapeles siempre ha supuesto un obstáculo de seguridad para los navegadores. Sin los permisos adecuados, una página podría copiar silenciosamente todo type of content malicioso en el portapapeles de un usuario que produciría resultados catastróficos al pegarlo. Imagina una página Web que copia silenciosamente rm -rf / or a
decompression pump picture
to your clipboard.

prompt-5760362

The permission request for the Clipboard API.

Giving web pages unrestricted read access to the clipboard is even more problematic. Users routinely copy sensitive information such as passwords and personal data to the clipboard, which can then be read by any page without the user's knowledge.

Como ocurre con muchas API nuevas, la API del Portapapeles solo es compatible con las páginas publicadas mediante HTTPS. Para ayudar a prevenir el abuso, el acceso al portapapeles solo está permitido cuando una página es la pestaña activa. Las páginas en pestañas activas pueden escribir en el portapapeles sin solicitar permiso, pero leer desde el portapapeles siempre necesita permiso.

Permissions have been incorporated to copy and paste to the
Permissions API. the clipboard-write permission is automatically granted to pages when they are the active tab. the clipboard-read Permission must be requested, which you can do by trying to read data from the clipboard. The following code shows the latest:

const queryOpts = { yam: 'clipboard-read', allowWithoutGesture: false };
const permissionStatus = await navigator.permissions.query(queryOpts);
console.log(permissionStatus.state);


permissionStatus.onchange = () => {
console.log(permissionStatus.state);
};

You can also control whether a user gesture is needed to invoke cut or paste using the allowWithoutGesture option. The default value for this value varies by browser, so you should always check it in.

This is where the asynchronous nature of the Clipboard API really comes in handy: attempting to read or write data from the clipboard automatically prompts the user for permission if it hasn't already been granted. Since the API is based on promises, this is completely transparent, and a user denying the clipboard permission causes the promise to be rejected so that the page can respond appropriately.

Because Chrome only enables clipboard access when a page is the active tab, you will find that some of the examples here do not run if pasted directly into DevTools, since DevTools itself is the active tab. There is a trick: defer clipboard access using setTimeout (), then quickly click inside the page to focus on it before calling the functions:

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

Feature detection

To use the Async Clipboard API while it is cross-browser compatible, try
navigator.clipboard and resort to previous methods. As an example, this is how you can implement pasting to include other browsers.

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

That is not the whole story. Before the Async Clipboard API, there was a combination of different copy and paste implementations in web browsers. In most browsers, the copy and paste function of the browser can be activated through
document.execCommand ('copy') and document.execCommand ('paste'). If the text to be copied is a string that is not present in the DOM, it must be injected into the DOM and selected:

button.addEventListener('click', (and) => {
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.');
}
});

In Internet Explorer, you can also access the clipboard using
window.clipboardData. If accessed within a user gesture, such as a click event, that is part of responsibly asking for permission, no permission message is displayed.

Population

You can play around with the Async Clipboard API in the demos below. You could get a
NotAllowedError si se ejecuta en un iframe, eso es provocado por el recién implementado
clipboard Function Policy. For this case, run the demo. directly in Glitch.

The first example shows how to move text on and off the clipboard.

To test the API with images, use this demo. Remember that only PNGs are supported and only in
[a few browsers] (https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API.

Next steps

Chrome is actively working to expand the Asynchronous Clipboard API with simplified events aligned to the
Drag and drop API. Debido a los riesgos potenciales, Chrome está pisando con cuidado. Para mantenerse actualizado sobre el progreso de Chrome, mire este post y nuestro Blog para conseguir actualizaciones.

For now, clipboard API support is available at
various browsers.

Happy copying and pasting!

Thanks

The Asynchronous Clipboard API was implemented by Darwin huang and Gary Kačmarčík. Darwin also provided the proof. Thanks to Kyarik and again to Gary Kačmarčík for reviewing parts of this post.

Hero image of Markus Winkler in
Unsplash.