We've looked at the motivations, and the legacy solutions, and now we turn to the options for copying data to the clipboard from client-side JavaScript.
Select and Copy 👎
This is the original solution I used (to wit the legacy solution). It relies on the use of document.createRange
and Range.selectNodeContents()
for selecting an element and document.execCommand('copy')
to copy it to clipboard. Code samples and pros and cons are discussed in the previous article.
The Clipboard Text API 👎
Cliboard interfaces have been evolving in Javascript. They are in demand. And the Clipboard Text API is widely supported now, via navigator.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 ...
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 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 standard. That is, can contain multiple parts defined by a MIME type. The select and copy approach (above), for example, puts two parts on the clipboard one with 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 for mailing and can, with the 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 👎
A step closer, this API lets us put parts of any MIME type on the clipboard. navigator.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 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.
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
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 as desktop clients and Gmail, Yahoo Mail and Office 365 Outlook as readers and except for Thuderbird they all ignore the <style>
tag and CSS variables are all lost as well.
The HTML5 Copy Event 👎
This is an experimental technology still and has very poor browser support alas. The idea is nice. Instantiate a ClipboardEvent and then dispatch the event. Vipul Patel described it loosely on HTML Goodies, but it's poorly documented, poorly supported and not a current contender. This may be the future, but it is not the today.
The Clipboard Event Handler 👍
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
property on which we can setData
. A full solution to this is elegantly presented by Petr Žoček on Stack Overflow.
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.
Top comments (0)