jQueryを用いたシンプルなクリップボードコピー実装ガイド

「ワンクリックでテキストをクリップボードにコピーする」機能はシェアボタン・コードブロック・招待URLなど様々な場面で使われます。

以前よく使われた document.execCommand("copy")現在非推奨・廃止済みです。この記事ではモダンな Clipboard APInavigator.clipboard.writeText())を使った実装をjQueryと組み合わせて解説します。

この記事でわかること

  • Clipboard API(navigator.clipboard.writeText)の基本と注意点
  • コピー成功時のフィードバックUI(ボタン変化・トースト通知)
  • コードブロックへのコピーボタン追加
  • URL・入力欄・動的テキストのコピーパターン
  • execCommandとの違い・フォールバック実装

注意: navigator.clipboardHTTPS環境(または localhost)でのみ動作します。HTTP環境では使用できません。

スポンサーリンク

Clipboard API の基本

navigator.clipboard.writeText() はPromiseを返します。コピー成功・失敗をハンドリングできるのが特長です。

// 基本構文
navigator.clipboard.writeText("コピーしたいテキスト")
  .then(function () {
    console.log("コピーしました");
  })
  .catch(function (err) {
    console.error("コピーに失敗しました:", err);
  });

// async/await で書く場合
async function copyText(text) {
  try {
    await navigator.clipboard.writeText(text);
    console.log("コピーしました");
  } catch (err) {
    console.error("コピーに失敗しました:", err);
  }
}

jQueryと組み合わせた基本実装

ボタンをクリックしたら指定したテキストをコピーし、ボタンの文字を一時的に変えてフィードバックを与えます。

HTML

<p id="copyTarget">https://example.com/invite?code=ABC123</p>
<button class="copy-btn" data-target="#copyTarget">
  ? コピー
</button>

CSS

.copy-btn {
  padding: .4rem .9rem;
  background: #0284c7;
  color: #fff;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: .9rem;
  transition: background .2s;
}
.copy-btn:hover  { background: #0369a1; }
.copy-btn.copied { background: #16a34a; }  /* 成功時: 緑 */

jQuery

$(function () {
  $(".copy-btn").on("click", function () {
    const $btn    = $(this);
    const target  = $btn.data("target");
    const text    = $(target).text().trim();

    navigator.clipboard.writeText(text)
      .then(function () {
        // ボタンを一時的に「コピーしました」に変える
        $btn.addClass("copied").text("✓ コピーしました");
        setTimeout(function () {
          $btn.removeClass("copied").text("? コピー");
        }, 2000);
      })
      .catch(function () {
        alert("コピーに失敗しました。手動でコピーしてください。");
      });
  });
});

トースト通知でフィードバックを表示する

ボタンを変化させるのではなく、画面端にトースト通知を出す実装です。

<!-- トースト用のコンテナ(body末尾に配置) -->
<div id="toast" role="status" aria-live="polite"></div>
#toast {
  position: fixed;
  bottom: 1.5rem;
  left: 50%;
  transform: translateX(-50%) translateY(60px);
  background: #1e293b;
  color: #fff;
  padding: .6rem 1.2rem;
  border-radius: 6px;
  font-size: .9rem;
  opacity: 0;
  transition: opacity .25s ease, transform .25s ease;
  z-index: 9999;
  pointer-events: none;
  white-space: nowrap;
}
#toast.show {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}
function showToast(message, duration) {
  duration = duration || 2000;
  const $toast = $("#toast").text(message).addClass("show");
  setTimeout(function () { $toast.removeClass("show"); }, duration);
}

// コピーボタンと連携
$(".copy-btn").on("click", function () {
  const text = $($(this).data("target")).text().trim();
  navigator.clipboard.writeText(text)
    .then(function ()  { showToast("✓ クリップボードにコピーしました"); })
    .catch(function () { showToast("コピーに失敗しました"); });
});

実践パターン

パターン1: コードブロックにコピーボタンを追加する

技術ブログやドキュメントサイトでよく見る「コードをコピー」ボタンを全 pre 要素に自動追加します。

.code-wrap {
  position: relative;
}
.code-copy-btn {
  position: absolute;
  top: .5rem;
  right: .5rem;
  padding: .25rem .6rem;
  background: rgba(255,255,255,.15);
  color: #fff;
  border: 1px solid rgba(255,255,255,.3);
  border-radius: 4px;
  font-size: .75rem;
  cursor: pointer;
  transition: background .2s;
}
.code-copy-btn:hover  { background: rgba(255,255,255,.25); }
.code-copy-btn.copied { background: #16a34a; border-color: #16a34a; }
$(function () {
  // すべての pre をラップしてコピーボタンを追加
  $("pre").each(function () {
    const $pre = $(this);
    $pre.wrap('<div class="code-wrap"></div>');
    $pre.parent().append(
      $('<button class="code-copy-btn" type="button">コピー</button>')
    );
  });

  // イベント委譲でコピーボタンを処理
  $(document).on("click", ".code-copy-btn", function () {
    const $btn  = $(this);
    const text  = $btn.closest(".code-wrap").find("pre").text();
    navigator.clipboard.writeText(text).then(function () {
      $btn.addClass("copied").text("✓ コピー済み");
      setTimeout(function () {
        $btn.removeClass("copied").text("コピー");
      }, 2000);
    });
  });
});

パターン2: URLシェアボタン(現在のURL)

$("#shareUrlBtn").on("click", function () {
  navigator.clipboard.writeText(location.href)
    .then(function ()  { showToast("URLをコピーしました"); })
    .catch(function () { showToast("コピーに失敗しました"); });
});

パターン3: input欄の値をコピー

<input type="text" id="inviteCode" value="ABC-123-XYZ" readonly>
<button id="copyCode">コードをコピー</button>
$("#copyCode").on("click", function () {
  const text = $("#inviteCode").val();
  navigator.clipboard.writeText(text)
    .then(function () {
      showToast("招待コードをコピーしました");
      // 入力欄を一時的にハイライト
      $("#inviteCode").addClass("copied-highlight");
      setTimeout(function () {
        $("#inviteCode").removeClass("copied-highlight");
      }, 1500);
    });
});

応用:readText() でクリップボードの内容を読み取る

navigator.clipboard.readText() を使うと、クリップボードに入っているテキストをJavaScriptで取得できます。初回実行時にブラウザがアクセス許可を求めます。

$("#pasteBtn").on("click", function () {
  navigator.clipboard.readText()
    .then(function (text) {
      // 取得したテキストを入力欄にセット
      $("#pasteTarget").val(text);
      showToast("貼り付けました: " + text.slice(0, 20) + (text.length > 20 ? "…" : ""));
    })
    .catch(function (err) {
      // ユーザーが許可しなかった場合
      alert("クリップボードへのアクセスが許可されていません");
      console.error(err);
    });
});

注意: readText() はユーザーが「クリップボードを読み取る」許可を明示的に与える必要があります。ページ読み込み時の自動実行は必ず失敗します。また Safari では対応が限定的なため、ユーザーへの代替手段(手動ペーストのガイド)を用意しておくのが安全です。

writeText() と readText() の比較

メソッド 役割 許可ダイアログ 主な用途
writeText(text) クリップボードに書き込む 通常不要 コピーボタン・シェア機能
readText() クリップボードから読み取る 初回要求あり 貼り付けボタン・フォーム補助

execCommand との比較とフォールバック

項目 execCommand(“copy”)
(非推奨)
Clipboard API
(推奨)
ステータス 非推奨・多くのブラウザで廃止予定 現在の標準
非同期 同期(Promiseなし) Promise(async/await対応)
HTTPS要件 不要(HTTPでも動作) HTTPS または localhost のみ
エラーハンドリング 戻り値のbooleanのみ .catch() で詳細なエラー取得可
ユーザー操作 クリックイベント内であれば動作 同様(ユーザー操作起点が必要)

HTTPサイト向けフォールバック実装

HTTP環境では navigator.clipboard が使えないため、フォールバックとして旧式の execCommand を使う実装例です。

function copyToClipboard(text) {
  // Clipboard API が使える場合(HTTPS推奨)
  if (navigator.clipboard && window.isSecureContext) {
    return navigator.clipboard.writeText(text);
  }

  // フォールバック: 一時的なテキストエリアを使う
  const $textarea = $("<textarea>")
    .val(text)
    .css({ position: "fixed", top: "-9999px", left: "-9999px" })
    .appendTo("body");
  $textarea[0].focus();
  $textarea[0].select();
  document.execCommand("copy");
  $textarea.remove();
  return Promise.resolve();  // 統一的にPromiseを返す
}

// 使い方(変わらない)
copyToClipboard("コピーしたいテキスト")
  .then(function ()  { showToast("コピーしました"); })
  .catch(function () { showToast("コピーに失敗しました"); });

よくある質問(FAQ)

Q. navigator.clipboard が undefined になります
A. HTTPS環境でない(HTTPサイト)か、古いブラウザを使っている可能性があります。window.isSecureContext で判定し、フォールバック実装に切り替えてください。
Q. コピーできないブラウザはありますか?
A. Clipboard APIは主要なモダンブラウザ(Chrome・Firefox・Safari・Edge)で対応しています。Internet Explorerは非対応です。Can I Use で最新のサポート状況を確認できます。
Q. ユーザーの操作なしにコピーできますか?
A. できません。Clipboard APIはセキュリティ上の理由から、クリックなどのユーザー操作を起点とした処理の中でのみ動作します。自動実行(タイマーなど)では Permission denied エラーになります。
Q. コピーした内容を読み取る(貼り付け内容を取得する)こともできますか?
A. はい。navigator.clipboard.readText() でクリップボードの内容を取得できます。ただし初回実行時にブラウザが「クリップボードを読み取る許可」をユーザーに求めます。
Q. WordPressで使う場合はどこにコードを書けばよいですか?
A. 子テーマの functions.php で wp_enqueue_scripts を使いjQueryを読み込み、カスタムJSファイルにコードを記述するのが標準的な方法です。投稿ごとに使う場合はカスタムフィールドやブロックエディタのカスタムHTMLブロックも使えます。

あわせて読みたい

まとめ

クリップボードコピー実装のポイント

  • navigator.clipboard.writeText() がモダンな標準。execCommand は非推奨
  • Clipboard APIはHTTPS環境ユーザー操作起点が必要
  • コピー後はボタン変化やトースト通知でフィードバックを必ず与える
  • HTTP環境向けには window.isSecureContext で判定してフォールバックを用意する
  • コードブロックへの自動ボタン追加はブログ・ドキュメントサイトで特に有用

Clipboard APIはシンプルなインターフェースで非常に使いやすくなっています。コピー機能を一から実装する場合は navigator.clipboard.writeText() を第一選択肢にしてください。