Копирование в буфер обмена

navigator.clipboard.writeText — современный способ скопировать текст по клику на кнопку с визуальным подтверждением.

Задача

Кнопка «Скопировать» рядом с кодом, ссылкой или токеном — нажал, текст в буфере, кнопка подтвердила это визуально.

Решение

<div class="copy-block">
  <code class="copy-block__text" id="copyText">npm install my-package</code>
  <button class="copy-btn" id="copyBtn" aria-label="Скопировать">
    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
      <rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>
    </svg>
    <span class="copy-btn__label">Скопировать</span>
  </button>
</div>
.copy-block {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 12px 16px;
  background: #1e293b;
  border-radius: 8px;
}

.copy-block__text { color: #e2e8f0; font-family: monospace; font-size: 0.9rem; flex: 1; }

.copy-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  background: #334155;
  color: #e2e8f0;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  font-size: 0.8rem;
  transition: background 0.2s;
  white-space: nowrap;
}
.copy-btn:hover { background: #475569; }
.copy-btn.copied { background: #16a34a; color: #fff; }
const btn  = document.getElementById('copyBtn');
const text = document.getElementById('copyText');
const label = btn.querySelector('.copy-btn__label');

async function copyToClipboard(str) {
  try {
    await navigator.clipboard.writeText(str);
    return true;
  } catch {
    // Fallback для браузеров без Clipboard API (редкость)
    const ta = document.createElement('textarea');
    ta.value = str;
    ta.style.position = 'fixed';
    ta.style.opacity = '0';
    document.body.appendChild(ta);
    ta.select;
    document.execCommand('copy');
    ta.remove();
    return true;
  }
}

btn.addEventListener('click', async () => {
  const ok = await copyToClipboard(text.textContent.trim());
  if (!ok) return;

  btn.classList.add('copied');
  label.textContent = 'Скопировано!';

  setTimeout(() => {
    btn.classList.remove('copied');
    label.textContent = 'Скопировать';
  }, 2000);
});

Ключевые моменты

  • navigator.clipboard.writeText — async, требует HTTPS или localhost; самый современный способ.
  • execCommand('copy') — устаревший fallback; работает через программный select на <textarea>.
  • Визуальная обратная связь (смена текста кнопки на 2 сек) — обязательна: пользователь должен знать, что произошло.
  • aria-label на кнопке — важен, если кнопка только иконка.

Варианты

  • navigator.clipboard.read / readText — чтение из буфера; требует разрешения пользователя.
  • Для React: хук useCopyToClipboard с состоянием copied.

Связанные рецепты / темы