Javascript でクリップボードにコピーする


はじめに

Javascript でクリップボードからのコピー&ペーストを行う主な方法は2つある。

  • document.execCommand()copypaste コマンドを実行する
  • navigator.clipboard オブジェクトでクリップボードを操作する

document.execCommand() は非推奨扱いであり、将来的に削除される可能性がある。

navigator.clipboard は、document.execCommand() を使用したクリップボードへのアクセスを置き換えるように設計されているが、比較的新しいAPIであり、全てのブラウザで互換性があるわけではない。

クリップボードへのコピー(writewriteText)だけを使うのであれば、ブラウザ互換性も十分なので navigator.clipboard を使っておけば良いと思う。


document.execCommand() による入力テキストのクリップボードコピー

テキストボックスのテキストは以下のようにしてクリップボードにコピーできる。

<input id="text" type="text" />
<button id="copy">Copy</button>

<script>
function copy() {
  let text = document.querySelector("#text");
  text.select();
  document.execCommand("copy");
}
document.querySelector("#copy").addEventListener("click", copy);
</script>


document.execCommand() によるノードコンテンツのクリップボードコピー

selectNodeContents() でノード子を選択して selection に追加してコピーする。

<span id="text">Text to be copied</span>
<button id="copy">Copy</button>

<script>
function copy() {
  let element = document.querySelector("#text");

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

  const selection = window.getSelection();
  selection.removeAllRanges();
  selection.addRange(range);

  document.execCommand("copy");
}
document.querySelector("#copy").addEventListener("click", copy);
</script>

display: none; のような非表示のノードはコピーできないため element.style.display = ""; のように表示状態にするか、document.createElement() で新しく要素を作成して、ノードをコピーしてから処理することになる。


document.execCommand() によるノードのクリップボードコピー

テーブルのコピーは selectNode() でノード全体を選択してコピーする。

<table id="table">
  <thead>
    <tr>...</tr>
  <thead>
  <tbody>
    ...
  </tbody>
</table>
<button id="copy">Copy</button>

<script>
function copy() {
  let element = document.querySelector("#table");

  let range = document.createRange();
  range.selectNode(element);

  let selection = window.getSelection();
  selection.removeAllRanges();
  selection.addRange(range);

  document.execCommand("copy");
}
document.querySelector("#copy").addEventListener("click", copy);
</script>

この場合、HTML がコピーされるため、テキスト要素だけをコピーしたい場合は、テキストエリアにテキストコンテンツを設定してコピーする。

<script>
function copy() {
  let element = document.querySelector("#table");

  let ta = document.createElement('textarea');
  ta.value = element.textContent;
  ta.style.opacity = "0";
  ta.style.position = "absolute";
  document.body.appendChild(ta);
  ta.select();
  document.execCommand("copy");
  ta.remove();
}
document.querySelector("#copy").addEventListener("click", copy);
</script>


navigator.clipboard でクリップボードを直接制御できる。

  • navigator.clipboard.readText() :テキストデータの読み込み
  • navigator.clipboard.writeText() :テキストデータの書き込み
  • navigator.clipboard.read() :画像やHTMLなどのリッチコンテンツの読み込み
  • navigator.clipboard.write() :画像やHTMLなどのリッチコンテンツの書き込み

readText()read() は、ブラウザによりサポート状況に注意が必要。

戻り値は Promise となっているため以下のように扱える。

navigator.clipboard.writeText("xxx").then(
  () => {
    /* 成功 */
  },
  () => {
    /* 失敗 */
  },
);


<input id="text" type="text" />
<button id="copy">Copy</button>

<script>
function copy() {
  let text = document.querySelector("#text");
  navigator.clipboard.writeText(text.value).then(
    () => alert("Copied"));
}
document.querySelector("#copy").addEventListener("click", copy);
</script>


text/html としてクリップボードにコピー。

<table id="table">
  <thead>
    <tr>...</tr>
  <thead>
  <tbody>
    ...
  </tbody>
</table>
<button id="copy">Copy</button>

<script>
function copy() {

  let element = document.querySelector("#table");

  const type = "text/html";
  const blob = new Blob([element.outerHTML], { type });
  const data = [new ClipboardItem({ [type]: blob })];
  navigator.clipboard.write(data);
}

document.querySelector("#copy").addEventListener("click", copy);
</script>

画像なども同じようにして扱える。