5
6

クリップボードにテキストをコピーさせる機能を作った時、Document is not focusedになったら確認したいこと

Last updated at Posted at 2024-01-24

以下の記事は、2024/1/19時点で最新バージョンの
Google Chrome(120.0.6099.234)にて検証しております

わざわざドラッグして、Ctrl + cなんてしなくても
ボタンを押しただけでクリップボードにテキストをコピーしてくれる。

文明とはありがたいものですね。

webブラウザ上に、ユーザーに何か文章をコピーさせる機能を搭載させるなら
クリップボードAPIのwriteText()メソッドを使用すると良いでしょう。1

write_text.js
navigator.clipboard.writeText('コピーさせたいテキスト');

コピーするボタンを画面上に用意してあげれば、きっとユーザーに喜ばれること間違いなし!
そうそう、コピーが成功したことがわかりやすいように、alertで教えてあげるのもいいですね。
我ながらなんて親切なんでしょう!

write_text.html
<p id="copied-text">この文章をコピーするよ</p>
<button id="copy-btn" class="button">コピーする!</button>

<script>
  const text = document.getElementById('copied-text').textContent;

  document.getElementById('copy-btn').addEventListener('click', () => {
    navigator.clipboard.writeText(text);
    alert('クリップボードにコピーしました!');
  });
</script>

さて、実際にボタン押下でテキストがコピーできるかどうか、試してみると…

chrome-capture-2024-0-10.gif

あれ?コピーができていませんね…

Document is not focused

上のサンプルコードのページで、”コピーする”ボタンを押下しても
クリップボードへのコピーが失敗してしまいます。

コンソールにエラーが出ているので、確認してみると…

DOMException: Document is not focused.

と、あります。

このエラーの通り、ページ自体にフォーカスが当たっていないと、clipboard.writeText()は失敗します。
例えば、開発者ツールのコンソールから、clipboard.writeText()を実行しようとしてもエラーになる訳です。

しかし、今回の場合、押下したボタンはページ上にあるのに、なぜこのエラーが出てしまうのでしょうか。

clipboardAPIは非同期処理

clipboardAPIの全てのメソッドは、非同期に動作します。
そのため、上のサンプルの様なコードだと、clipboard.writeText()の実行完了を待たずにalert()が動作します。
結果、フォーカスがアラートのダイアログにある状態になってしまうため、コピーに失敗してしまったんですね😮

alertを出したければ、処理の完了を待ってあげよう

clipboard.writeText()を実行した後、動作させたい処理がある場合は
以下のサンプルの様に、then()メソッドを用いて、コピーの処理の完了を待ってあげる様にしましょう。2

write_text_fixed1.html
<p id="copied-text">この文章をコピーするよ</p>
<button id="copy-btn" class="button">コピーする!</button>

<script>
  const text = document.getElementById('copied-text').textContent;

  document.getElementById('copy-btn').addEventListener('click', () => {
    navigator.clipboard.writeText(text).then(() => {
      alert('クリップボードにコピーしました!')
    });
  });
</script>

または、async/await を用いても以下の様に実装できますね!

write_text_fixed2.html
<p id="copied-text">この文章をコピーするよ</p>
<button id="copy-btn" class="button">コピーする!</button>

<script>
  const text = document.getElementById('copied-text').textContent;

  document.getElementById('copy-btn').addEventListener('click', async () => {
    await navigator.clipboard.writeText(text);
    alert('クリップボードにコピーしました!');
  });
</script>

無事、コピーすることができました!

まとめ

  • ページ自体にフォーカスが当たっていないと、clipboard.writeText()はエラーになってしまう😵
  • clipboard.writeText()後に何らかの処理をさせたい場合は、then(), またはasync/awaitで処理の完了を待つ様にしましょう👏
  1. execCommand()メソッドは、非推奨となっているのでクリップボードAPIに互換しましょう。
    また、IEではそもそもnavigator.clipboardが使用できない様なので、IEからの利用がある場合は注意が必要です。

  2. clipboard.writeText()の戻り値はPromiseオブジェクトです。then()で処理をつなげることで非同期処理の実行結果を待つことができます。

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6