Как скопировать текст в буфер обмена с помощью JavaScript?
Современное решение: Clipboard API (асинхронный и безопасный)
Лучший способ на сегодняшний день — использовать Clipboard API, а именно метод navigator.clipboard.writeText(). Этот API работает асинхронно (возвращает Promise) и не требует создания временных элементов. Он поддерживается во всех современных браузерах (Chrome 66+, Firefox 63+, Safari 13.1+, Edge 79+).
Базовый пример
async function copyToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
console.log('Текст скопирован!');
} catch (err) {
console.error('Ошибка копирования: ', err);
}
}
// Использование:
document.getElementById('copyBtn').addEventListener('click', () => {
const text = document.getElementById('myText').innerText;
copyToClipboard(text);
});
Важные нюансы
- Контекст безопасности: Clipboard API работает только в защищенном контексте (HTTPS или localhost). На обычном HTTP он будет недоступен.
- Разрешения: Браузер может запросить разрешение у пользователя при первом вызове. Лучше обрабатывать ошибку, если пользователь отказал.
- Вызов из обработчика события: Метод должен вызываться в ответ на действие пользователя (клик, нажатие клавиши), иначе браузер может заблокировать его.
Универсальное решение с fallback (для поддержки старых браузеров)
Если нужно поддерживать старые браузеры (например, IE11 или старые версии Safari), используйте комбинацию Clipboard API и резервного метода с execCommand:
function fallbackCopyTextToClipboard(text) {
const textArea = document.createElement("textarea");
textArea.value = text;
textArea.style.position = "fixed"; // Избегаем прокрутки
textArea.style.opacity = 0;
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
const successful = document.execCommand('copy');
if (successful) {
console.log('Скопировано через fallback');
} else {
console.error('Не удалось скопировать');
}
} catch (err) {
console.error('Ошибка fallback: ', err);
}
document.body.removeChild(textArea);
}
async function copyToClipboardModern(text) {
if (!navigator.clipboard) {
// Clipboard API не поддерживается
fallbackCopyTextToClipboard(text);
return;
}
try {
await navigator.clipboard.writeText(text);
console.log('Скопировано через Clipboard API');
} catch (err) {
console.error('Ошибка Clipboard API, пробуем fallback: ', err);
fallbackCopyTextToClipboard(text);
}
}
Советы для лучшего UX
- Не используйте
alert()после копирования — это раздражает. Лучше покажите всплывающее уведомление (toast) или измените текст кнопки на "Скопировано!". - Для копирования из
inputилиtextareaможно использоватьselect()+execCommandкак запасной вариант, но Clipboard API предпочтительнее. - Всегда проверяйте, что вы копируете строку. Если нужно скопировать HTML-содержимое (с форматированием), используйте
navigator.clipboard.write()с объектомClipboardItem, но это сложнее.
В итоге: для 95% современных проектов достаточно простого navigator.clipboard.writeText(). Добавьте fallback только если вам нужно поддерживать IE11 или очень старые версии браузеров.
Альтернативный подход: копирование через выделение текста
Если вы не хотите использовать Clipboard API по каким-то причинам (например, из-за строгих политик безопасности), можно обойтись старым добрым способом с document.execCommand('copy'), но с небольшим улучшением — не создавать элемент в DOM, а использовать уже существующий элемент input или textarea на странице.
function copyFromInput(elementId) {
const input = document.getElementById(elementId);
if (!input) return;
// Сохраняем текущее положение курсора
const currentStart = input.selectionStart;
const currentEnd = input.selectionEnd;
input.select();
input.setSelectionRange(0, 99999); // Для мобильных устройств
try {
document.execCommand('copy');
console.log('Скопировано из поля ввода');
} catch (err) {
console.error('Ошибка копирования: ', err);
}
// Восстанавливаем выделение
input.setSelectionRange(currentStart, currentEnd);
input.blur();
}
Плюсы: не нужно создавать временные элементы, работает быстро.
Минусы: требует наличия видимого или скрытого textarea/input на странице, execCommand помечен как устаревший и может быть удален в будущих версиях браузеров.
Этот метод подходит для простых случаев, когда вы точно знаете, что пользователь работает в десктопном браузере, и не хотите заморачиваться с асинхронностью. Но для продакшена я рекомендую первый вариант с Clipboard API.