「ワンクリックでテキストをクリップボードにコピーする」機能はシェアボタン・コードブロック・招待URLなど様々な場面で使われます。
以前よく使われた document.execCommand("copy") は現在非推奨・廃止済みです。この記事ではモダンな Clipboard API(navigator.clipboard.writeText())を使った実装をjQueryと組み合わせて解説します。
この記事でわかること
- Clipboard API(navigator.clipboard.writeText)の基本と注意点
- コピー成功時のフィードバックUI(ボタン変化・トースト通知)
- コードブロックへのコピーボタン追加
- URL・入力欄・動的テキストのコピーパターン
- execCommandとの違い・フォールバック実装
注意: navigator.clipboard は HTTPS環境(または 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)
あわせて読みたい
まとめ
クリップボードコピー実装のポイント
navigator.clipboard.writeText()がモダンな標準。execCommandは非推奨- Clipboard APIはHTTPS環境とユーザー操作起点が必要
- コピー後はボタン変化やトースト通知でフィードバックを必ず与える
- HTTP環境向けには
window.isSecureContextで判定してフォールバックを用意する - コードブロックへの自動ボタン追加はブログ・ドキュメントサイトで特に有用
Clipboard APIはシンプルなインターフェースで非常に使いやすくなっています。コピー機能を一から実装する場合は navigator.clipboard.writeText() を第一選択肢にしてください。