Copy to Clipboard: The Options
Tags: javascript, clipboard, copy
Published: 2021-10-22 12:38:28

We've looked at the [motivations](https://dev.to/thumbone/the-thing-is-on-awesomeness-and-motivation-5bo9-temp-slug-9559983), and the [legacy solutions](https://dev.to/thumbone/copy-to-clipboard-first-cut-1j5j), and now we turn to the options for copying data to the clipboard from client-side JavaScript.

# Select and Copy :thumbsdown:
This is the original solution I used (to wit the legacy solution). It relies on the use of [`document.createRange`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createRange) and [`Range.selectNodeContents()`](https://developer.mozilla.org/en-US/docs/Web/API/Range/selectNodeContents) for selecting an element and [`document.execCommand('copy')`](https://developer.mozilla.org/en-US/docs/Web/API/document/execCommand) to copy it to clipboard. Code samples and pros and cons are discussed in the [previous article](https://dev.to/thumbone/copy-to-clipboard-first-cut-1j5j).

# The Clipboard Text API :thumbsdown:

Cliboard interfaces have been evolving in Javascript. They are in demand. And the Clipboard Text [API](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API) is widely supported now, via [`navigator.clipboard.writeText()`](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/writeText). This can put text onto the clipboard. The text I experimented with was simply `outerHTML` of the element I want to copy. And it works fine, bar the rather deep shortcoming that it's text ... 

![Sad Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cbzt599deshq9i46hct3.png)

What does that even mean? How is HTML  not text? To understand that, it's useful to have a tool that can look at the clipboard in a little more detail. [CopyQ](https://hluk.github.io/CopyQ/) is just such a tool that comes well recommended and lets us look at the clipboard internals a little.

It becomes clear that the clipboard contents follow the [MIME](https://en.wikipedia.org/wiki/MIME) standard. That is, can contain [multiple parts](https://en.wikipedia.org/wiki/MIME#Multipart_messages) defined by a MIME type. The select and copy approach ([above](#select-and-copy-thumbsdown)), for example, puts two parts on the clipboard one with [media type](https://en.wikipedia.org/wiki/Media_type) `text/html` and one `text/plain`. When you paste this clipboard, if the recipient is HTML ready, the former is pasted, and if not the latter. The paster (the one pasting text) decides what format they are most prepared to accept, the copier (the one copying the text) can only provide as many MIME parts as to cover a possible paster's needs.

The problem with the Text API is that it can only put a `text/plain` part on the clipboard and if we put the `outerHTML` of our element in that part, it pastes as HTML (source code).

The classic use case (and the one that drives my interest) is pasting it into a mailer. If an HTML string is in a `text/html` part it pastes as rendered HTML and looks like it looks in the browser (within limitations - the very limitations driving this exploration). 

If the HTML is in a `text/plain` part then it pastes as HTML source code into the mailer. Not the desired outcome.

It was not a bad bridging solution for me though. Something to experiment with as I use [Thunderbird](https://www.thunderbird.net/en-US/) for mailing and can, with the [ThunderHTMLedit](https://addons.thunderbird.net/en-US/thunderbird/addon/thunderhtmledit/) extension, paste the HTML into the source for an email I'm drafting. Works OK, but is clumsy. 

All the same that let me test what kind of HTML can be sent and how it's received by various clients. Which is essentially exploring questions regarding what HTML to put on the clipboard. More on that later.

### The Clipboard Generic API :thumbsdown:

A step closer, this API lets us put parts of any [MIME type](https://en.wikipedia.org/wiki/Media_type) on the clipboard. [`navigator.clipboard.write()`](https://developer.mozilla.org/en-US/docs/Web/API/Clipboard/write) is the method of interest and it can put blobs of any type on the clipboard. That works much better that the Text API but ...

If copying only the element's `outerHTML` to the clipboard and pasting that into a HTML ready context, the styling disappears. Element's are associated with [classes](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/class) but no styling information for those classes is provided in the pasted copy (it rests in style sheets or in `<style>` tags elsewhere on the document, that were not copied and did not get pasted). So in the copy, all the class declarations fail to resolve and the styling information is lost.

![I got no style](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nm7tvmt82wqa6er2zmp6.jpg)

OK, easy fixed. We can add a `<style> </style>` tag to the HTML we're copying and include all the styles needed. These are all available in [`document.styleSheets`](https://developer.mozilla.org/en-US/docs/Web/API/Document/styleSheets) where each sheet contains `cssRules` which we can copy into a `<style>` tag and all is good. 

In fact, paste that HTML with the `<style>` into Thunderbird and it's then fully styled, and beautiful again. But ... and oh _isn't there always a but_. The world hates `<style>` tags it seems! At least the world of email does.

If copied to the clipboard as `text/html`, when pasted into an emailer and then sent, the `<style>` tag is ignored by most clients it seems. Pretty much the only email client that will honour it is Thunderbird. I tested Thunderbird and [Outlook](https://www.microsoft.com/en-au/microsoft-365/p/outlook/CFQ7TTC0HLKQ) as desktop clients and [Gmail](http://gmail.com/), [Yahoo Mail](https://mail.yahoo.com) and [Office 365 Outlook](https://outlook.office365.com) as readers and except for Thuderbird they all ignore the `<style>` tag and CSS variables are all lost as well.

### The HTML5 Copy Event :thumbsdown:

This is an experimental technology still and has very poor browser support alas. The idea is nice. Instantiate a [ClipboardEvent](https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent) and then dispatch the event.  [Vipul Patel](https://www.htmlgoodies.com/author/vipul-patel/) described it loosely on [HTML Goodies](https://www.htmlgoodies.com/html5/working-with-clipboard-apis-in-html5-web-apps/), but it's poorly documented, poorly supported and not a current contender. This may be the future, but it is not the today.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vji87w3p0eig27nt9zpl.gif)

### The Clipboard Event Handler :thumbsup:

It happens that the copy command `document.execCommand('copy')` simply triggers a `copy` event, and that we can add our own listener to that event: `document.addEventListener('copy', our_event_handler)` . 

Inside of this, the copy event has a [`clipboardData`](https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent/clipboardData) property on which we can [`setData`](https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/setData). A full [solution](https://stackoverflow.com/a/45352464/4002633) to this is elegantly presented by [Petr Žoček](https://stackoverflow.com/users/4284586/petr-%c5%bdo%c4%8dek) on [Stack Overflow](https://stackoverflow.com).

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/flfo21f0f5twz77sdakf.jpg)

This, in fact, works brilliantly and is the chosen solution, that I've run with (thanks a heap, Petr!). 

We can choose the strings and MIME types freely with this handler. It's the most flexible, widely supported and the most reliable way I've found of placing material onto the clipboard.

But this still raises the spectre of *_what_* to copy to the clipboard.