DEV Community

Alexey Boyko
Alexey Boyko

Posted on

JavaScript. Work with clipboard, Ctrl+C Ctrl+V

How to write an image to the clipboard. What data types can be written to the clipboard. Custom types support. How to make custom copy/paste buttons.

Pic 1. Copy between tabs and Google DocsPic 1. Copy between tabs and Google Docs

Task

Create a copy function for the dgrm.net flowchart editor.

  • Copy-paste between tabs
  • Paste to Word/Google docs -> diagram is inserted as a picture.
  • Hot keys support: Ctrl+C, Ctrl+V, Ctrl+X
  • Custom copy/paste buttons for work with mouse
  • Mobile device support

Clipboard APIs

document.execCommand('copy') don’t work

This API is deprecated and doesn’t work. Don’t try to use it to bypass restrictions of other APIs.

'copy', 'paste', 'cut' event handlers

document.addEventListener('copy', evt => {
 evt.preventDefault();
 evt.clipboardData.setData('text/plain', 'text to clipboard');
});

// Listing 1. Wright to clipboard on ‘copy’ event
Enter fullscreen mode Exit fullscreen mode

In this option, there is no way to make your own ‘copy’ button, the user must press Ctrl + C.

navigator.clipboard.read/wright

btn.addEventListener('click', async _ => 
 await navigator.clipboard.writeText('text to clipboard')
);

// Listing 2. Write to clipboard on button click
Enter fullscreen mode Exit fullscreen mode

You can make a custom “copy” button. Works in all browsers and on mobile devices.

Safari has a limitation: This API cannot be used in callbacks. This does not work in Safari:

btn.addEventListener('click', async _ => 
 // create png from svg
 svgToPng(
  svg,
  // callback
  async png => await navigator.clipboard.write(...))
);

// Listing 3. Don’t work in Safari.
// navigator.clipboard is not allowed in callbacks.
// How to write an image to clipboard in the next part
Enter fullscreen mode Exit fullscreen mode

This is a security limitation: it is not clear when the callback comes, the user may already have changed his mind about copying.

You can do this: first write the string to the clipboard, if the browser allows -> write the image.

// guaranteed clipboard write
await navigator.clipboard.writeText('text to clipboard');

// try to write img
// if ok -> clipboard will be overwritten
try {
 // create png from svg
 svgToPng(
  svg,
  // callback
  async png => await navigator.clipboard.write(...));
} catch { }

// Listing 4. Write text to clipboard,
// if the browser allows -> write the image
Enter fullscreen mode Exit fullscreen mode

How to write an image to the clipboard

await navigator.clipboard.write([new window.ClipboardItem({
 'image/png': Promise.resolve(png), // png is Blob
 'text/plain': Promise.resolve(new Blob(['text to clipboard'], { type: 'text/plain' }))
})]);

// Listing 5. Write image and alternative text to the clipboard
Enter fullscreen mode Exit fullscreen mode

You can write several data types to the clipboard at the same time. For example image and text. If pasted into Word -> a picture is inserted, if into Notepad -> text is inserted.

You can write to clipboard this types:

  • text/plain
  • text/html
  • image/png

Some browsers allow more types. These three are allowed everywhere.

You can write to the clipboard only PNG. Other image formats are not allowed.
When copying, the browser “cleanses” the png. To be safe, the browser removes metadata from png.
Trouble for dgrm.net. Dgrm.net stores a schema description in metadata. Thanks to metadata, you can open the picture for editing — Pic. 2.

Pic 2. dgrm.net can open diagrams from PNG imagesPic 2. dgrm.net can open diagrams from PNG images

Custom data types in clipboard

‘text/plain’ from the clipboard can be pasted anywhere. It’s good to use a custom data type that only your application reads. For example ‘text/dgrm’.

For security, the browser associates custom type with domain. Thus, a third-party site will not read your data type from the clipboard.

Not all browsers support custom types. In Chrome, from some version you can use custom types, they must be prefixed with ‘web ‘ -> ‘web text/dgrm’.

Not all browsers allow writing non-’text/plain’ type to the clipboard using navigator.clipboard.write. They allow use of navigator.clipboard.write only in ‘copy’, ‘cut’ event handlers. Those. you can’t make your own “copy” button.

As a result you may prefer to use navigator.clipboard.writeText, it works everywhere.

Read from clipboard

Reading from the clipboard is even more dangerous than writing. Even more restrictions. In FireFox, you can only read in the ‘paste’ event handler. You cannot make a custom“insert” button, you need the user to press Ctrl V.

document.addEventListener('paste', evt => {
 const txt = evt.clipboardData.getData('text/plain');
});

// Listing 6. Read from clipboard on ‘paste’ event
Enter fullscreen mode Exit fullscreen mode

Other browsers allow us to use the navigator.clipboard API.

btn.addEventListener('click', async _ => 
 await navigator.clipboard.readText()
);

// Listing 7. Read from clipboard on button click
Enter fullscreen mode Exit fullscreen mode

The browser will ask for the user’s permission. iOS Safari will ask every time navigator.clipboard.readText is called.

About dgrm.net flowchart editor

Dgrm.net is a quick editor without extra buttons.

I am developing the editor. I write announcements in https://twitter.com/boyko_tech.

Try it, write what you like / don’t like. I keep a list of proposals.

Top comments (0)