This is the original solution I used (to wit the legacy solution). It relies on the use of
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.
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.
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.
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.
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) .
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.