クリップボードにコピーするボタン(JavaScriptとReact)
クリップボードにコピーするボタン
JavaScriptとReactで作るクリップボードコピーボタン | We.Inc
Clipboard APIのwriteTextでコピーボタンを作ります。動くデモ、Reactフック、ClipboardItemによるリッチなHTMLや画像のコピー、アクセシブルな「コピーしました」通知とエラー処理まで。
クリックハンドラーからnavigator.clipboard.writeText(text)を呼び出します。プロミスを返すので完了を待ち、短い「コピーしました」のメッセージを表示して、エラーの場合も捕捉します。このAPIはHTTPSかlocalhostでしか動かず、クリックのような実際のユーザー操作が必要なので、ページ読み込み時には呼ばないでください。
クリップボードにデータを入れる方法
- navigator.clipboard.writeText()
- プレーンテキスト
- Baseline、2020年3月から幅広く利用可能
- navigator.clipboard.write([new ClipboardItem(...)])
- テキスト、HTML、PNG画像
- ClipboardItemはBaseline 2024
- copy イベントと event.clipboardData.setData()
- 通常のCtrl+Cでコピーされる内容を変更
- 幅広くサポート
- document.execCommand("copy")
- 現在の選択範囲
- 非推奨、新しいコードでは避ける
コピーボタンは簡単そうに見えますが、上位に表示されるスニペットの多くは、うまくいかない部分を省いています。プロミスが拒否されることもあり、埋め込みフレームではブロックされることもあり、スクリーンリーダーの利用者には何が起きたのか伝わりません。下のデモはブラウザーで実際にコピーし、コードはそれぞれのケースに対応しています。
- デモのコピーボタンを押します。ラベルが2秒間「コピーしました」に変わり、非表示のステータスメッセージがそれを読み上げます。
- テスト用のボックスに貼り付けて、クリップボードに何が入ったかを正確に確認します。
- リッチコピーのボタンを試し、メールや文書エディターに貼り付けて、HTML版が書式を保つことを確かめます。
- 下にあるプレーンなJavaScript、Reactフック、リッチコピーのコードをコピーします。
- 拒否には必ず対処しましょう。「Ctrl+Cを押してコピーしてください」のような表示を出してテキストを選択し、手作業で完了できるようにします。
- 成功はrole="status"の領域で読み上げましょう。アイコンを変えるだけでは、スクリーンリーダーの利用者には何も伝わりません。
- ラベルが「コピーしました」に切り替わってもボタンの幅が変わらないようにし、周りの要素がずれないようにしましょう。
- 値は装飾された要素の表示テキストではなく、データからコピーしましょう。表示テキストは非表示の空白や余分な空白を拾うことがあります。
- 埋め込みフレーム内では、Chromiumの場合、親がPermissions Policyでclipboard-writeを許可する必要があります。例えばallow="clipboard-write"です。
よくある質問
navigator.clipboardが未定義になるのはなぜですか?
ページが安全なコンテキストにないからです。Clipboard APIはHTTPSのページとlocalhostでしか公開されないため、プレーンなHTTPやローカルネットワークのアドレスで配信されたサイトでは使えません。
writeTextがNotAllowedErrorを投げるのはなぜですか?
ブラウザーが書き込みを拒否したためです。多くは、直前のユーザー操作がなかった、ページにフォーカスがなかった、またはフレームがPermissions Policyでブロックされたことが原因です。クリックハンドラー内で直接呼び出し、その前に時間のかかる待機処理を置かないようにしましょう。
Reactでクリップボードにコピーするのにライブラリは必要ですか?
いいえ。writeTextを包む10行ほどのフックで十分です。ライブラリが主に加えるのは、とても古いブラウザー向けのexecCommandによる代替処理で、現在のブラウザーには不要です。
画像をクリップボードにコピーできますか?
はい。navigator.clipboard.writeと、キーがimage/png、値がPNGのBlobであるClipboardItemを使います。事前にClipboardItem.supports()で形式を確認しましょう。ブラウザーが最も確実に受け付ける形式はPNGです。
document.execCommand('copy')はまだ使っても大丈夫ですか?
非推奨です。条件次第で多くのブラウザーではまだ動きますが、新しいコードでは非同期のClipboard APIを使い、失敗時は手動でコピーしてもらう方法に切り替えましょう。
ブラウザーが課す3つのルール
- クリップボードへの書き込みは特権的な操作のため、ブラウザーは安全なページとフォーカスのある文書を求めます。さらにFirefoxとSafariでは、書き込みのたびに新しいユーザー操作が必要です。Chromiumでは、クリップボード書き込みの永続的な権限を付与することもできます。
- 実際には、クリックやキー入力からコピーを始め、ハンドラーの早い段階で書き込み、失敗は例外ではなく普通に起こるものとして扱いましょう。
利用者が気づけるフィードバック
- ラベルを2秒ほど「コピーしました」に切り替え、その後元に戻します。ホバー時にだけ出るツールチップは、タッチ画面やキーボードの利用者には見えません。
- 同じメッセージを控えめなライブリージョンにも入れましょう。role="status"なら、スクリーンリーダーが読んでいる内容を遮らずに読み上げます。
リッチなコピーと独自のcopyイベント
- ClipboardItemは、text/plain版とtext/html版を同時に保持できます。HTMLを理解するアプリは書式付きのほうを、プレーンテキストの入力欄はもう一方を貼り付けます。
- 出典の行を加えるなど、通常のCtrl+Cでコピーされる内容を変えたいときは、copyイベントを監視してevent.preventDefault()を呼び、event.clipboardData.setData()で独自のデータを設定します。
プレーンなJavaScript
フィードバックと代替処理付きのコピーボタン
ステータス要素は見た目には隠れていますが、読み上げられます。失敗時はテキストが選択されるので、Ctrl+CまたはCmd+Cを押してもらえます。
Reactフック
useCopyToClipboard
状態とコピー関数を返します。アンマウント時にタイマーを解除するため、削除されたコンポーネントを更新することはありません。
リッチテキスト、画像、copyイベント
プレーンテキストの代替付きでHTMLをコピーする
各MIMEタイプが1つのBlobです。貼り付け先は、理解できる最もリッチな形式を選びます。
通常のコピーに出典の行を加える
使いすぎに注意しましょう。コピー内容を変えると嫌がられることがあるので、出典が役立つ引用やコードに限りましょう。
エラーとその原因
コピーに失敗するとき
- navigator.clipboard が未定義
- プレーンなHTTPで配信されている
- HTTPSで配信するか、localhostでテストする
- NotAllowedError
- ユーザー操作がない、またはタブにフォーカスがない
- クリックハンドラー内で呼び出す
- 埋め込みフレーム内での NotAllowedError
- Permissions Policyがクリップボードへの書き込みをブロックしている
- iframeにallow="clipboard-write"を追加する
- 画像のコピーが拒否される
- 未対応のMIMEタイプ
- PNGに変換し、ClipboardItem.supports()で確認する
コピーしました
失敗しました
コピー
リッチテキストをコピー
クリップボードにコピーしました
コピーに失敗しました。テキストを選択してCtrl+CまたはCmd+Cを押してください。
試してみる
プレーンテキスト用とリッチなHTML用のコピーボタンです。結果を確認する貼り付け用ボックスもあります。
コピーするテキスト
招待:
チームに参加
ここに貼り付けて確認(Ctrl+VまたはCmd+V)
無料で始める · クレジットカード不要
関連: ガイド|Webマーケティングと集客を学ぶ
製品
ご利用いただける方
機能
リソース
会社情報
サイトマップを見る