Pasting native HTML to browser clipboard

Viewed 231

With a button click, a user will have HTML content from the current page into the clipboard. Then, in an email, paste the content with the HTML formatting preserved. The desire is to replicate the selecting of content in the browser window, without making the user do the selecting (separate view).

I have most of this setup and working. I don't believe there are permissions issues. However, with the below code, I get "pasted", yet then pasting (CTRL+V) following that, there is nothing in the paste buffer. If I switch it to clipboard.writeText(), I get the html as plaintext. It's just using the Blob for html that causes the paste buffer to be empty.

I think it relates to the Blob part, maybe the text/html part is wrong? Is there a way to get this to work?

<div id="lipsum" contenteditable="true" style="display: none;">
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
  <p>Vivamus mollis, augue eu vulputate fermentum.</p>
</div>
<script>
(function() {
  let html = document.getElementById('lipsum').innerHTML
  let content = new Blob([ html ], { type: 'text/html' })
  let data = [ new ClipboardItem({ [ content.type ]: content }) ]
  
  window.focus()

  setTimeout(() => {
    navigator.clipboard.write(data).then(
      () => console.log('pasted'),                   <<< This fires
      (error) => console.log('not pasted', error)
    )
  }, 2000)
})()
</script>
1 Answers

Your code worked for me on Chrome. I was able to paste the div contents after loading the page and waiting a couple seconds. I did notice errors if I didn't continuously have the page focused. E.g. when I would keep the inspector window forward it would error.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Test</title>
</head>
<body>
<div id="lipsum" contenteditable="true" style="display: none;">
  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
  <p>Vivamus mollis, augue eu vulputate fermentum.</p>
</div>

<script>
  (function() {
    let html = document.getElementById('lipsum').innerHTML
    let content = new Blob([ html ], { type: 'text/plain' })
    let data = [ new ClipboardItem({ [ content.type ]: content }) ]

    setTimeout(() => {
      window.focus()
      navigator.clipboard.write(data).then(
        () => console.log('pasted'),
        (error) => console.log('not pasted', error)
      )
    }, 2000)
  })()</script>
</body>
</html>
Related