読み込み中...

JavaScriptによるクリップボードコピー機能の実装方法と実例10選

JavaScriptを使ってクリップボードにコピーする方法のイメージ JS
この記事は約33分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

現在のクリップボードコピーはnavigator.clipboard.writeText()を第一候補にし、未対応環境だけdocument.execCommand()へ退避させる設計が扱いやすいです。JavaScriptのコードスニペットでも、ウェブ開発のコピーUIでも、この順序なら失敗時の分岐を整理できます。

動作確認環境
  • HTML Living Standard / ECMAScript 2024
  • Google Chrome 126 / Firefox 127 / Safari 17.5 を想定した記述
  • HTTPS または localhost の secure context を前提

ブラウザからOSのクリップボードへ触れる処理は、クリックやタップなどのユーザー操作に結び付けます。buttonaddEventListener()clickを組み合わせると、JavaScriptの処理意図も明確になるのが基本です。

公式ドキュメントでは、MDNのClipboard APIが安全なコンテキストでの非同期読み書きを扱います。一方、MDNのdocument.execCommand()は非推奨APIのため、新規のJavaScriptプログラミングでは主役にしません。

テキスト、共有URL、認証コード、コードスニペットをコピーするUIは同じ考え方で組み立てられます。Promiseasyncawaittry...catchまで含めると、JavaScriptのエラー時の流れも追いやすくなるのが目安です。

📖 この記事で学べること
  • クリップボードへテキストをコピーする基本形
  • コードスニペット向けのボタンUIと成功表示
  • Clipboard APIと旧方式の使い分け
  • 読み取り、上書き、HTMLデータ操作の考え方
  • HTTPS、権限、ユーザー操作に関する注意点
分類要素用途実装時の判断
API選定writeTextテキストコピー新規実装の第一候補
旧方式execCommand選択範囲コピーフォールバック用途
権限clipboard-write書き込み許可ブラウザ差に注意
権限clipboard-read読み取り許可ユーザー確認が絡む
環境secure contextHTTPS条件localhostは例外扱い
イベントclickユーザー操作自動実行を避ける
要素textarea一時領域旧方式で使う
要素button操作開始明示的なUI
取得getElementById単一要素ID指定向け
取得querySelectorCSSセレクタ柔軟な選択
取得getElementsByClassName複数要素まとめてコピー
配列Array.from配列化mapと併用
配列map変換テキスト抽出
配列join連結改行連結
表示innerText表示文字列CSS影響を受ける
表示textContentテキスト全体非表示も含み得る
非同期Promise完了通知thenでも扱える
非同期async/await待機読みやすい構造
例外try...catch失敗処理権限拒否に対応
データBlobバイナリ表現HTML書き込みにも使う
データClipboardItemMIME単位writeで使う
形式text/plain平文最も扱いやすい
形式text/htmlHTML対応確認が必要
読み取りreadText文字列取得許可が必要
読み取りread複合データ取得MIME確認が必要
書き込みwriteText文字列保存コピーUI向け
書き込みwrite複合保存画像やHTML向け
判定navigator.clipboard対応確認分岐に使う
判定queryCommandSupported旧方式確認非推奨API周辺
通知setTimeout一時表示成功メッセージ向け

クリップボードにコピーする機能の考え方

クリップボードコピーは、ページ上の文字列をOS側の一時保存領域へ渡す仕組みです。ウェブ開発ではフォーム入力、招待URL、トークン、コードスニペットの共有に使われます。

ページが勝手に読み書きできるとプライバシー上の問題が出るため、ブラウザはsecure contexttransient activationを求めます。コピー対象はvalueinnerTextから取り出し、成功時は短いフィードバックを返す構成が実用的です。関連するイベント処理はJavaScriptイベント徹底解説!30個の使い方と応用例も確認できるのがポイントです。

💡 Tips: コードスニペットの横に置くコピーボタンは、押した直後の状態変化まで用意すると、コピーされたかどうかをユーザーが判断しやすくなります。

基本的なクリップボードコピーの実装

基本形では、textareaの文字列を選択してdocument.execCommand('copy')を呼び出します。このAPIは非推奨ですが、既存JavaScriptの保守やフォールバックでは理解しておく価値があるのが一般的です。

新しくJavaScriptを書くならnavigator.clipboard.writeText()を優先します。旧方式では一時的なtextareaを作り、select()で選択範囲を作る流れを押さえます。

サンプルコード1:テキストをクリップボードにコピー

最小に近い構成です。HTML側は入力欄とボタン、JavaScript側は対象要素の取得と選択範囲の作成だけです。

<textarea id='myText'>コピーしたいテキスト</textarea>
<button id='copyButton'>コピー</button>

結果: 期待される表示は、テキスト入力欄とコピー用ボタンが並ぶ形になります。

idtextareabuttonを識別すると、JavaScriptからgetElementById()で直接取得できます。

function copyText() {
  var textArea = document.getElementById('myText');
  textArea.select();
  document.execCommand('copy');
  textArea.setSelectionRange(0, 0);
}
document.getElementById('copyButton').addEventListener('click', copyText);

結果: 期待される動きは、ボタン押下時に入力欄の文字列がクリップボードへ入ることです。

select()で範囲を作り、execCommand()でコピー処理を呼びます。execCommand()は互換目的に限定するのが妥当です。

コピーしたいテキスト
[コピー]

結果: 期待される表示は、コピーしたいテキストが入った入力欄とボタンです。

ボタンを押すとtextarea内の文字列がクリップボードへ送られます。選択範囲が残らないよう、setSelectionRange()でカーソル位置を戻するのが現実的です。

サンプルコード2:HTML要素の内容をコピー

任意のHTML要素をコピーする場合は、一時的なtextareaへ文字列を移して選択します。表示用のdivpも旧方式で扱えます。

<div id='myContent'>
  <h2>コピーしたい内容</h2>
  <p>この部分の内容をクリップボードにコピーすると覚えるとよいでしょう。</p>
</div>
<button id='copyButton'>コピー</button>

結果: 期待される表示は、見出しと説明文を含む領域の下にコピーボタンがある状態です。

div内のテキストをまとめてコピー対象にするため、コードスニペットや利用規約の抜粋にも応用できると整理できます。

function copyContent() {
  var contentElement = document.getElementById('myContent');
  var tempTextArea = document.createElement('textarea');
  tempTextArea.value = contentElement.innerText;
  document.body.appendChild(tempTextArea);
  tempTextArea.select();
  document.execCommand('copy');
  document.body.removeChild(tempTextArea);
}
document.getElementById('copyButton').addEventListener('click', copyContent);

結果: 期待される動きは、表示領域の文字列が一時要素を経由してクリップボードへ入ることです。

createElement()で一時要素を作り、appendChild()で文書へ加え、コピー後にremoveChild()で片付けます。

コピーしたい内容
この部分の内容をクリップボードにコピーします。
[コピー]

結果: 期待される表示は、見出しと本文が改行を含んだ文字列としてコピー対象になる形です。

innerTextは表示上の改行やCSSの影響を受けますし、ここがポイントです。正確なテキストノードを扱う場合はtextContentも候補です。

JavaScriptでのクリップボード操作の応用

実用画面では、コピー後の文言変更、複数要素の結合、失敗時の案内をJavaScriptで組み合わせます。認証コードやコマンドラインのコードスニペットでは、コピー操作の成功表示がミスの軽減につながります。

複数要素のコピーでは配列処理を使うため、forEach・mapの使い分け術10選の内容ともつながりますが、これは押さえたい点です。

サンプルコード3:コピー成功のフィードバックをユーザーに提供

コピー後に短いメッセージを出すと、操作完了を判断しやすくなります。成功表示はdisplayを切り替えるだけでも実装できます。

<div>
  <p id='myText'>コピーしたいテキスト</p>
  <button id='copyButton'>コピー</button>
  <span id='copyMessage' style='display: none;'>コピーしました!</span>
</div>

結果: 期待される表示は、テキスト、コピー用ボタン、非表示の成功メッセージを持つ小さな領域です。

spanを用意し、初期状態をdisplay: noneにすると理解できます。ボタン押下後だけinlineへ変えます。

function copyText() {
  var text = document.getElementById('myText').innerText;
  var temp = document.createElement('textarea');
  temp.value = text;
  document.body.appendChild(temp);
  temp.select();
  document.execCommand('copy');
  document.body.removeChild(temp);
  var message = document.getElementById('copyMessage');
  message.style.display = 'inline';
  setTimeout(function() {
    message.style.display = 'none';
  }, 2000);
}
document.getElementById('copyButton').addEventListener('click', copyText);

結果: 期待される動きは、コピー後に成功メッセージが短時間だけ表示されることです。

このJavaScriptではsetTimeout()で表示時間を制御します。失敗時も同じ場所へメッセージを出せるため、console.error()だけに頼らないUIへ拡張できます。

コピーしたいテキスト
[コピー]

結果: 期待される表示は、コピー対象テキストとボタンが並び、押下後に成功文が一時表示される形です。

ボタンのラベルを「コピー済み」に変える方法もあると覚えるとよいでしょう。再操作しやすいよう、setTimeout()で元へ戻す設計が扱いやすいです。

サンプルコード4:複数のテキストを一度にコピー

複数行をまとめる場合は、対象要素を集めて配列へ変換し、改行で連結します。プログラミング記事のコマンド一覧や設定値一覧でも使いやすい形です。

<div>
  <p class='copyText'>テキスト1</p>
  <p class='copyText'>テキスト2</p>
  <p class='copyText'>テキスト3</p>
  <button id='copyButton'>まとめてコピー</button>
</div>

結果: 期待される表示は、複数のテキスト行とまとめてコピーするボタンです。

同じclassを付けた複数要素をコピー対象にします。IDを増やすより、同じ役割の要素をまとめて扱えます。

function copyMultipleText() {
  var textElements = document.getElementsByClassName('copyText');
  var textArray = Array.from(textElements).map(function(element) {
    return element.innerText;
  });
  var textToCopy = textArray.join('n');
  var temp = document.createElement('textarea');
  temp.value = textToCopy;
  document.body.appendChild(temp);
  temp.select();
  document.execCommand('copy');
  document.body.removeChild(temp);
}
document.getElementById('copyButton').addEventListener('click', copyMultipleText);

結果: 期待される動きは、複数の文字列が改行区切りでクリップボードへ保存されることです。

Array.from()map()join()の流れで、変換と結合の役割が読み取りやすくなります。

テキスト1
テキスト2
テキスト3
[まとめてコピー]

結果: 期待されるコピー内容は、テキスト1、テキスト2、テキスト3が改行で並ぶ文字列です。

まとめコピーは、ユーザーが選んだ複数項目を一度に貼り付けたい場面にも合います。イベントの組み合わせが増える場合は、JavaScriptにおけるイベントハンドラを完全ガイド!20選の実践サンプルコード付きも参考になると考えられます。

クリップボードAPIの詳細な解説

Clipboard APIは、navigator.clipboardから非同期にクリップボードへアクセスする仕組みです。現在のJavaScriptでは、document.execCommand()よりClipboard APIを優先する方針が自然です。

このAPIはhttps:のページやlocalhostなどの安全なコンテキストを前提にします。ローカルで動いたコードをHTTP配信へ置くと、ウェブ開発の本番画面で失敗する可能性があります。

⚠️ 注意: execCommand()は非推奨のため、新規実装の中心には置かず、Clipboard APIが使えない場合の退避策として扱うのが現実的です。

サンプルコード5:クリップボードAPIを使用した高度な例

テキストの書き込みだけならwriteText()が最短です。戻り値はPromiseなので、完了と失敗をtry...catchで分けますし、これが一つの目安です。

async function copyTextToClipboard(text) {
  try {
    await navigator.clipboard.writeText(text);
    console.log('テキストのコピーに成功しました');
  } catch (err) {
    console.error('テキストのコピーに失敗しました: ', err);
  }
}
copyTextToClipboard('コピーしたいテキスト');

結果: 期待される出力は、権限と環境が満たされる場合に成功メッセージがコンソールへ出ることです。

awaitで書き込み完了を待ってからログを出します。失敗時はDOMExceptionなどをユーザー向け表示へ変換します。

テキストのコピーに成功しました

結果: 期待される出力は「テキストのコピーに成功しました」です。

この出力はブラウザ条件が満たされた場合の例です。ユーザー操作なし、HTTP配信、フォーカスなしの状態では失敗することがあると言えるでしょう。

サンプルコード6:非同期クリップボードAPIの利用

読み取りは書き込みより制限が強くなりがちです。read()readText()は、許可や操作タイミングの影響を受けます。

async function getClipboardContents() {
  try {
    const clipboardItems = await navigator.clipboard.read();
    for (const clipboardItem of clipboardItems) {
      for (const type of clipboardItem.types) {
        const blob = await clipboardItem.getType(type);
        console.log(`MIMEタイプ: ${type}`);
        console.log(`データ: ${await blob.text()}`);
      }
    }
  } catch (err) {
    console.error('クリップボードの読み取りに失敗しました:', err);
  }
}
document.getElementById('pasteButton').addEventListener('click', getClipboardContents);

結果: 期待される出力は、読み取れた各データのMIMEタイプとテキスト内容です。

ClipboardItemを走査し、typesからMIMEタイプを取り出します。各データはBlobとして返るため、テキスト化にはblob.text()を使います。

MIMEタイプ: text/plain
データ: コピーされたテキスト

結果: 期待される出力は、MIMEタイプとコピー済みテキストがコンソールに並ぶ形です。

ブラウザは同じ権限モデルで動くわけではありません。Chromium系、Firefox、Safariでは読み取り時の許可やプロンプトの扱いが異なるため、失敗時の案内が必要です。

よくあるエラーと対処法

クリップボードのエラーは、文法ミスより実行条件の不足で起きることが多いです。Document is not focused、HTTPSでないページ、ユーザー操作外の呼び出しに注意します。

エラー処理はコピー処理と同じ段階で設計します。catchで失敗を拾い、画面には手動コピーなどの代替案を出するのが基本です。

セキュリティ制限によるエラーとその回避方法

代表的な失敗例は、ドキュメントがフォーカスされていない状態の呼び出しです。ユーザーがページを操作しているとブラウザが判断できず、クリップボードアクセスが拒否されます。

Uncaught DOMException: Document is not focused.

結果: 期待される出力例は、フォーカス条件を満たさないときの例外メッセージです。

このエラーを避けるには、コピー処理をclickkeydownなどのユーザー操作に結び付けます。DOMContentLoadedだけで自動コピーする設計は避けますが、覚えておくと役立つでしょう。

<button id='copyButton'>コピー</button>

結果: 期待される表示は、コピー処理を開始するためのボタンです。

実際のクリップボード操作はイベントハンドラ内へ入れます。処理を別関数に分けても、呼び出し元がユーザー操作であることを保ちます。

document.getElementById('copyButton').addEventListener('click', function() {
  // クリップボードにコピーする処理をここに書く
});

結果: 期待される動きは、ボタンのクリックに応じてコピー処理が開始されることです。

この構造はセキュリティ制限に沿った自然な操作です。エラーを完全には消せないため、失敗時の表示も残するのが目安です。

ブラウザ互換性と対応

互換性対応では、APIの存在を確認してから処理を選びます。新規のJavaScriptではnavigator.clipboardの確認を優先し、queryCommandSupported()は旧方式理解に使います。

function isCopySupported() {
  return document.queryCommandSupported('copy');
}
if (isCopySupported()) {
  // document.execCommand('copy')を使ったコピー処理
} else {
  alert('クリップボードへのコピーはサポートされていません。手動でコピーしてください。');
}

結果: 期待される動きは、旧方式を使える場合と使えない場合で処理を分けることです。

この分岐は古い実装を読むときに役立ちますし、ここを基本と考えるとよいでしょう。alert()だけでは操作が中断されやすいため、実際のUIではページ内メッセージへ置き換えます。

[コピー]
クリップボードへのコピーはサポートされていません。手動でコピーしてください。

結果: 期待される表示は、未対応時に手動コピーを促す案内です。

新しい分岐ではnavigator.clipboardの有無を見ます。対応していればClipboard API、なければ旧方式や手動案内へ退避するのがポイントです。

if (navigator.clipboard) {
  // Clipboard APIを使ったコピー処理
} else {
  // document.execCommand('copy')を使ったコピー処理
}

結果: 期待される動きは、Clipboard APIの有無によって実行する処理が切り替わることです。

この判定は、共有URLや拡張子付きファイル名をコピーする画面にも使えます。ファイル名や拡張子の扱いはJavaScriptで拡張子を活用する方法12選!初心者でも簡単にできる方法を紹介と相性があります。

Clipboard APIを使ったコピー処理

結果: 期待される出力例は、Clipboard API側の処理が選ばれたことを示す文字列です。

対応していない環境では旧方式へ進みますし、ここがポイントです。旧方式は非推奨なので、可能なら手動コピーの手順も示します。

document.execCommand('copy')を使ったコピー処理

結果: 期待される出力例は、旧方式側の処理が選ばれたことを示す文字列です。

ブラウザ差は完全には消せません。機能検出、ユーザー操作、失敗時メッセージをセットにし、JavaScriptのコードスニペットごとに同じ型で実装すると保守しやすくなります。

クリップボードのデータ操作

コピーだけでなく、読み取りや上書きまで扱うとClipboard APIの範囲が広がりますが、これは押さえたい点です。クリップボード内のテキスト取得、整形、HTML形式と平文の同時書き込みも可能です。

読み取りはプライバシーへの影響が大きいため、ボタン操作と明確な説明を組み合わせます。ユーザーが何を読み取られるか理解できるUIが必要です。

サンプルコード7:クリップボードからのデータの取得

テキストだけ読む場合はreadText()を使います。空文字列や許可拒否もあるため、例外処理と空文字の扱いを分けますし、これが一つの目安です。

async function getClipboardText() {
  try {
    const text = await navigator.clipboard.readText();
    console.log('クリップボードのテキスト:', text);
  } catch (err) {
    console.error('クリップボードの読み取りに失敗しました:', err);
  }
}
document.getElementById('pasteButton').addEventListener('click', getClipboardText);

結果: 期待される出力は、読み取れたクリップボード内のテキストがコンソールに出ることです。

pasteButtonのクリックに合わせて読み取りを始めます。書き込みより許可条件が厳しいため、自動で読む設計は避けます。

クリップボードのテキスト: コピーされたテキスト

結果: 期待される出力例は、クリップボードのテキストがラベル付きで表示される形です。

許可が得られない場合は、貼り付け用のtextareaを表示してユーザーに手動操作してもらう代替策があるのが一般的です。

サンプルコード8:クリップボードデータの変更と操作

クリップボードの上書きにもwriteText()が使えます。ユーザーが押した更新ボタンから実行すれば、意図しないコピー内容の変更を避けやすくなります。

async function updateClipboardText() {
  const newText = 'これは新しいテキストです';
  try {
    await navigator.clipboard.writeText(newText);
    console.log('クリップボードのテキストが更新されました');
  } catch (err) {
    console.error('クリップボードの更新に失敗しました:', err);
  }
}
document.getElementById('updateButton').addEventListener('click', updateClipboardText);

結果: 期待される出力は、書き込みに成功した場合に更新完了のメッセージが出ることです。

固定文字列だけでなく、フォーム入力値や生成済みテキストも渡せます。プログラミング支援ツールでは、整形後のコマンドやテンプレートをコピーする用途に合います。

クリップボードのテキストが更新されました

結果: 期待される出力例は「クリップボードのテキストが更新されました」です。

HTMLと平文を同時に扱う場合はwrite()ClipboardItemを使いるのが現実的です。貼り付け先に応じて装飾付きHTMLと平文を使い分けられます。

async function replaceClipboardData() {
  const textData = new Blob(['これは新しいテキストデータです'], { type: 'text/plain' });
  const htmlData = new Blob(['<p>これは新しいHTMLデータです</p>'], { type: 'text/html' });
  try {
    await navigator.clipboard.write([
      new ClipboardItem({
        [textData.type]: textData,
        [htmlData.type]: htmlData
      })
    ]);
    console.log('クリップボードのデータが置き換えられました');
  } catch (err) {
    console.error('クリップボードの置き換えに失敗しました:', err);
  }
}
document.getElementById('replaceButton').addEventListener('click', replaceClipboardData);

結果: 期待される動きは、text/plainとtext/htmlのデータが同じClipboardItemとして書き込まれることです。

BlobへMIMEタイプを付け、ClipboardItemのキーとしてtext/plaintext/htmlを渡します。対応状況は異なるため、失敗時は平文のみへ戻す分岐も必要です。

クリップボードのデータが置き換えられました

結果: 期待される出力例は、クリップボードのデータが置き換わったことを示すメッセージです。

データ操作は、ウェブ開発の管理画面やCMSの編集支援で役立ちます。コードスニペットをHTMLとして貼り付けたい場面でも、平文との併用で失敗時の影響を抑えられますが、覚えておくと役立つでしょう。

クリップボード操作のセキュリティ面

クリップボードには、メールアドレス、認証コード、社内URLなどの機微な情報が入る可能性があります。JavaScriptから読み書きする機能は、ユーザーの意図、HTTPS、権限、表示フィードバックをまとめて設計します。

読み取りと書き込みは同じ軽さで扱いません。書き込みは共有を助けますが、読み取りはユーザーの手元の情報をページ側へ渡す操作なので、説明と同意が欠かせません。

ℹ️ 補足: Permissions APIのclipboard-readclipboard-writeは、ブラウザごとの差があるため、許可状態だけで全挙動を断定しない設計が必要です。

サンプルコード9:安全なクリップボードアクセスの実現

安全寄りのコピー関数では、Clipboard APIの有無を確認してから実行します。未対応の場合は旧方式へ退避し、対応環境ではwriteText()を使います。

async function copyTextToClipboard(text) {
  if (!navigator.clipboard) {
    fallbackCopyTextToClipboard(text);
    return;
  }
  try {
    await navigator.clipboard.writeText(text);
    console.log('テキストのコピーに成功しました');
  } catch (err) {
    console.error('テキストのコピーに失敗しました:', err);
  }
}
function fallbackCopyTextToClipboard(text) {
  const textArea = document.createElement('textarea');
  textArea.value = text;
  document.body.appendChild(textArea);
  textArea.select();
  document.execCommand('copy');
  document.body.removeChild(textArea);
}
document.getElementById('copyButton').addEventListener('click', () => {
  copyTextToClipboard('コピーするテキスト');
});

結果: 期待される動きは、対応環境ではClipboard API、未対応環境ではフォールバック処理が選ばれることです。

fallbackCopyTextToClipboard()を分離すると、将来execCommand()を外すときにも影響範囲を追いやすくなります。

テキストのコピーに成功しました

結果: 期待される出力例は、書き込みが成功した場合の成功メッセージです。

条件を満たさない場合は失敗します。ログだけで終わらせず、ボタン付近に案内文を出すと次の操作を判断しやすくなると整理できます。

テキストのコピーに失敗しました: DOMException: Document is not focused.

結果: 期待される出力例は、フォーカス条件などを満たさない場合の失敗メッセージです。

失敗はブラウザの保護機能として起きます。対象テキストを選択状態にする、手動コピー案内を出す、といった退避策が実用的です。

サンプルコード10:ユーザー許可の取得と管理

許可状態の確認にはnavigator.permissions.query()を使います。navigator.permissions.request()を広く使える前提にせず、この例では状態確認を中心に扱いると理解できます。

async function requestClipboardPermission() {
  try {
    const permissionStatus = await navigator.permissions.query({ name: 'clipboard-write' });
    if (permissionStatus.state === 'granted') {
      console.log('クリップボードへのアクセスが許可されています');
    } else if (permissionStatus.state === 'prompt') {
      console.log('クリップボードへのアクセスが許可されていません。ユーザーに許可を求めます。');
      const result = await navigator.permissions.query({ name: 'clipboard-write' });
      if (result.state === 'granted') {
        console.log('ユーザーがクリップボードへのアクセスを許可しました');
      } else {
        console.log('ユーザーがクリップボードへのアクセスを拒否しました');
      }
    } else {
      console.log('クリップボードへのアクセスが拒否されています');
    }
  } catch (err) {
    console.error('パーミッションのリクエストに失敗しました:', err);
  }
}
document.getElementById('requestPermissionButton').addEventListener('click', requestClipboardPermission);

結果: 期待される出力は、ブラウザが返す許可状態に応じたメッセージです。

clipboard-writeの状態を確認し、grantedpromptdeniedを分けます。ただし状態確認だけでコピー成功を保証するものではありません。

クリップボードへのアクセスが許可されています

結果: 期待される出力例は、アクセスが許可済みであることを示すメッセージです。

promptの場合は確認が必要になる可能性があります。コピーが必要な理由をボタン付近に示すと、操作の意味が伝わりやすくなると覚えるとよいでしょう。

クリップボードへのアクセスが許可されていません。ユーザーに許可を求めます。
ユーザーがクリップボードへのアクセスを許可しました

結果: 期待される出力例は、許可確認が必要な状態から許可済みへ進む場合のメッセージです。

拒否された状態では、同じ操作を繰り返しても成功しない場合があります。ブラウザ設定の確認を促すか、手動で選べるUIへ切り替えますし、ここを基本と考えるとよいでしょう。

クリップボードへのアクセスが拒否されています

結果: 期待される出力例は、クリップボードへのアクセスが拒否されていることを示すメッセージです。

セキュリティ面では、コピーする文字列を画面に表示し、押したボタンの近くで成功または失敗を伝えます。読み取り操作には明確な目的を添えます。

実装前に決めておきたい範囲

コピーする文字列が固定なのか、ユーザー入力から生成されるのかで設計が変わりますし、ここがポイントです。固定文字列ならdata-copy属性、入力欄ならinput.valuetextarea.valueを参照する構成が自然です。

表示テキストと実際にコピーされる文字列がずれる場合は、表示用のtextContentとコピー用データを分けます。JavaScriptのコードスニペットではインデントや改行が意味を持つため、trim()で削るか残すかも決めます。

秘密情報を含める設計は慎重に扱いると考えられます。アクセストークンや一時パスワードは、コピー後の非表示、一定時間での無効化、ログ抑制なども検討します。

共通関数へ渡す値をstringにそろえ、UI側は成功表示だけを担当させると、ウェブ開発の保守作業でも追跡しやすくなります。

UIに組み込むときの判断

コピー用ボタンは対象テキストの近くへ配置すると言えるでしょう。離れた場所に置く場合は、aria-labelやボタン文言で対象を補います。

成功メッセージは押したボタンの近くに出すほうが文脈を保てます。rolearia-liveを使う場合は、短い文言にして読み上げが過剰にならないようにするのが基本です。

複数のコードスニペットが並ぶ記事では、同じclassを付けてイベント委譲で処理できます。親要素にaddEventListener()を置き、押されたボタンから近いpreを探す構造なら、ブロックが増えてもJavaScriptを増やさずに済みます。

静的なページでは個別ID、CMSやSPAのように要素が増減する画面ではイベント委譲が現実的です。失敗時には対象文字列を選択状態にする、手動コピーの説明を出す、再試行ボタンを残す導線も置きますが、これは押さえたい点です。

保守しやすい関数設計

コピー処理の関数は文字列を受け取り、成功か失敗かを返す形にします。DOM取得、文字列の組み立て、クリップボードへの書き込み、画面表示を詰め込むとテストしにくくなります。

getCopyText()で対象文字列を作り、copyToClipboard()で書き込み、showCopyStatus()で表示を更新するのが目安です。コピー対象が一箇所だけなら素直な関数で十分で、複数箇所に増えた時点で共通化します。

Clipboard APIの使い方だけでなく、ユーザー操作、アクセシビリティ、エラー処理まで含めて小さな部品として捉えます。ウェブ開発で長く使うUIほど、この分離が後の修正負荷を下げますし、これが一つの目安です。

運用時に確認したい境界

運用では、コピー対象がユーザー入力値なのか、サーバーから返った値なのかを区別します。サーバー生成値は、表示前の整形やエスケープ処理まで含めて扱います。

HTMLとして表示する値とクリップボードへ入れる値は混同しません。画面側ではescapeHTML相当の処理を通し、コピー側では必要な改行やタブだけを残するのがポイントです。

コマンドや設定ファイルのコードスニペットでは、末尾の改行が意味を持つ場合があります。trim()を無条件に使わず、削る文字と残す文字を明確に決めます。

テスト観点として、空文字、長い文字列、絵文字、改行、HTMLタグのように見える文字列を用意するのが一般的です。JavaScriptの文法だけでなく、ブラウザごとの権限モデルや実行環境の条件も確認します。

コピー対象を安全に整形する考え方

コピー対象を整形するときは、ユーザーの入力を変えすぎないようにします。全角と半角、改行、インデント、引用符は貼り付け先で意味を持つため、画面上で確認できる状態にしてからクリップボードへ送りますが、覚えておくと役立つでしょう。

共有リンクなら余計な空白を除き、コードスニペットならインデントを保ち、CSV風の文字列なら区切り文字を明示します。用途ごとに整形ルールを変えることで、同じJavaScriptのコピー関数でも前処理を差し替えられます。

normalizeCopyText()のような関数を用意し、画面側のイベント処理から独立させますし、ここを基本と考えるとよいでしょう。過剰な整形は誤動作の原因になるため、ユーザー入力をそのまま使う場面と、システム生成値を整える場面を分けます。

コピー後に何をするのかを想定して文字列を作ることが、使いやすいクリップボード実装につながります。

失敗時の文言と再試行

失敗時のメッセージは、原因を断定しすぎない書き方にするのが現実的です。権限、フォーカス、HTTP配信、ブラウザ未対応など複数の原因があるため、「コピーできませんでした。文字列を選択して手動でコピーしてください」のように次の行動を示します。

開発者向けにはconsole.error()へ例外を残し、ユーザー向けには短い説明だけを見せます。再試行が有効なフォーカス不足と、権限拒否や未対応ブラウザのように手動案内へ切り替える場合を分けますし、ここがポイントです。

管理画面や入力フォームでは、対象テキストをreadonlyの入力欄にも表示すると、クリップボードAPIが使えない環境でも作業を継続できます。成功時は「コピーしました」、失敗時は「手動でコピーしてください」、未対応時は「ブラウザが対応していません」のように分けます。

補助表示は視覚的な成功通知だけに頼らない形で作りますが、これは押さえたい点です。aria-liveを使う場合は文言を短く保ち、連続クリックで同じ通知が何度も読み上げられないよう制御します。

コピー処理の戻り値をtrueまたはfalseにそろえ、表示側で文言を切り替える設計が扱いやすいです。公開記事のサンプル、管理画面のIDコピー、問い合わせ対応の定型文コピーも、対象文字列を作る処理だけ差し替えれば共通化できます。

コピー後に貼り付け先まで制御することはできません。ブラウザが許可するのはクリップボードへの読み書きであり、別アプリへの貼り付け操作はユーザー側に残りますし、これが一つの目安です。

まとめ

JavaScriptでクリップボードコピーを作るなら、テキスト書き込みはnavigator.clipboard.writeText()を中心に据えます。旧来のdocument.execCommand()は非推奨のため、既存コード理解やフォールバックに用途を絞ります。

コードスニペット、共有URL、認証コード、設定値などをワンクリックでコピーできる画面を作るには、try...catch、機能検出、手動操作への退避を組み合わせますが、覚えておくと役立つでしょう。JavaScriptの配列処理を深めたい場合は、JavaScriptのforEachでreturnを活用する6つのテクニックも関連知識として役立ちます。

著者: Japanシーモア編集部

Japanシーモアは、Web/IoT/APP/SYS 分野のプログラミング情報を体系的に提供するメディアです。本記事は編集部による執筆とAI支援を組み合わせて制作し、公開前に編集部が校正しています。誤りや改善案がございましたらお問い合わせよりご連絡ください。

※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。

関連記事