Clipboard api (range/Selection)

by Julien Roche

HTML

<div role="textbox" hidefocus="true" contenteditable="true" spellcheck="false" style="border: 1px solid black; height: 20vh;" aria-multiline="true">
Some text to <b>copy/paste</b> into various container
</div>

<br />
<hr />
<br />
<button>Click me for copy</button>
<br />
<br />
<hr />
<br />

<section style="display: flex;">
  <fieldset style="flex: 1 1 auto;">
    <legend>Simple textarea (text/plain)</legend>
    <textarea style="resize: none; height: 10vh; width: 100%;"></textarea>
  </fieldset>
  
  <fieldset style="flex: 1 1 auto;">
    <legend>Rich editor (text/html)</legend>
    <div role="textbox" hidefocus="true" contenteditable="true" spellcheck="false" style="border: 1px solid black; height: 10vh;"></div>
  </fieldset>
</section>

JavaScript

const editorElement = document.querySelector('div[role="textbox"]');
const buttonElement = document.querySelector('button');
buttonElement.addEventListener('click', () => {
	const copyCommandSuccess = copyInClipboard(editorElement.innerHTML);
  alert('Copy status: ' + copyCommandSuccess);
});


function copyInClipboard(content) {
	const element = document.createElement('div');
  element.setAttribute('contenteditable', 'true');
  element.setAttribute('style', 'position: absolute; left: -100%; top: -100%;');
  element.innerHTML = content;
  
  document.body.appendChild(element);

	try {
  	const selection = window.getSelection();
    const selectedRange = selection.rangeCount === 0 ? null : selection.getRangeAt(0);

    const range = document.createRange();
    range.selectNodeContents(element);

    selection.removeAllRanges();
    selection.addRange(range);

    const copyCommandSuccess = document.execCommand('copy');
    selection.removeAllRanges();

    if (selectedRange) {
      selection.addRange(range);
    }

    return copyCommandSuccess;
  } catch(e) {
  	document.body.removeChild(element);
  	return false;
  }
}