コピーボタンとは

クリックするとテキストをクリップボードにコピーし、ボタンの文字が「コピーしました」に一時的に変わるボタン。

概要

コードやリンクなど、決まった文字列をワンクリックでクリップボードにコピーできるボタンです。navigator.clipboard.writeText() でコピーし、成功したらボタンの文字を「コピーしました」に変えて、数秒後に元の表示へ戻します。クリップボード API が使えない環境(権限がブロックされている場合など)に備えて、対象のテキストを選択状態にするフォールバックも用意しておくと親切です。

別名

表記ゆれ:クリップボードにコピー、copy button

AI への伝え方

「このコードブロックにコピーボタンを付けて、押したら 2 秒だけ『コピーしました』に変わるようにして」のように、コピー対象と表示が戻るまでの秒数を伝えます。クリップボード API が使えない場合のフォールバックが必要かどうかも伝えると、対応範囲がぶれません。

似たパーツとの違い

「アイコンボタン」はアイコンだけで用途を示す汎用的なボタンで、コピーボタンはその用途をクリップボードへのコピーに限定した専用のボタンという関係です。

デモ

npm install seory-ui

コード

HTML
<div class="copy-button-demo">
  <div class="copy-button-demo__row">
    <code class="copy-button-demo__code" id="copy-button-demo-text">npm install seory-ui</code>
    <button class="copy-button-demo__button" type="button" data-copy-target="copy-button-demo-text">
      <span class="copy-button-demo__label" aria-live="polite">コピー</span>
    </button>
  </div>
</div>
CSS
.copy-button-demo {
  font-family: sans-serif;
}

.copy-button-demo__row {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 6px 6px 14px;
  border: 1px solid #b3b3b3;
  border-radius: 8px;
  background: #f2f2f2;
}

.copy-button-demo__code {
  font-family: monospace;
  font-size: 14px;
  color: #333;
}

.copy-button-demo__button {
  padding: 8px 14px;
  border: 0;
  border-radius: 6px;
  background: #0017c1;
  color: #fff;
  font-size: 13px;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

.copy-button-demo__button:hover {
  background: #00118f;
}

.copy-button-demo__button:focus-visible {
  outline: 2px solid #0017c1;
  outline-offset: 2px;
}

.copy-button-demo__button--done {
  background: #333;
}

@media (prefers-reduced-motion: reduce) {
  .copy-button-demo__button {
    transition: none;
  }
}
JS
const copyButtonDemoButton = document.querySelector(".copy-button-demo__button");
const copyButtonDemoLabel = copyButtonDemoButton.querySelector(".copy-button-demo__label");
const copyButtonDemoCode = document.getElementById(copyButtonDemoButton.dataset.copyTarget);
let copyButtonDemoResetTimer = null;

copyButtonDemoButton.addEventListener("click", async () => {
  const text = copyButtonDemoCode.textContent ?? "";

  try {
    if (!navigator.clipboard || !navigator.clipboard.writeText) {
      throw new Error("clipboard api unavailable");
    }
    await navigator.clipboard.writeText(text);
  } catch (error) {
    // クリップボード API が使えない場合は、対象のテキストを選択状態にする
    const range = document.createRange();
    range.selectNodeContents(copyButtonDemoCode);
    const selection = window.getSelection();
    selection?.removeAllRanges();
    selection?.addRange(range);
  }

  copyButtonDemoLabel.textContent = "コピーしました";
  copyButtonDemoButton.classList.add("copy-button-demo__button--done");
  clearTimeout(copyButtonDemoResetTimer);
  copyButtonDemoResetTimer = setTimeout(() => {
    copyButtonDemoLabel.textContent = "コピー";
    copyButtonDemoButton.classList.remove("copy-button-demo__button--done");
  }, 2000);
});