W3docs

JavaScript Clipboard API

Aprenda a Clipboard API assíncrona do JavaScript — copie e leia texto com navigator.clipboard, manipule dados ricos com ClipboardItem e entenda os requisitos de contexto seguro e permissões.

A Clipboard API moderna, exposta por meio de navigator.clipboard, é a forma assíncrona e baseada em promises de ler e gravar no clipboard do sistema. Ela substitui a abordagem antiga e síncrona com document.execCommand('copy') por métodos que retornam promises, combinando naturalmente com async/await. A API é distinta — mas frequentemente usada junto — dos eventos de clipboard cut, copy e paste: os eventos permitem interceptar o que o usuário faz, enquanto navigator.clipboard permite que seu código inicie ações de clipboard diretamente.

Gravando Texto no Clipboard

A tarefa mais comum é copiar texto. navigator.clipboard.writeText(text) aceita uma string, grava-a no clipboard e retorna uma Promise que resolve quando a gravação é bem-sucedida e rejeita quando falha.

Como retorna uma promise, a forma mais limpa de utilizá-la é dentro de uma função async com try...catch, para que você possa dar feedback ao usuário em ambos os casos:

<button id="copyBtn">Copy</button>
<span id="status"></span>
<script>
  const button = document.getElementById('copyBtn');
  const status = document.getElementById('status');

  button.addEventListener('click', async () => {
    try {
      await navigator.clipboard.writeText('Hello from W3docs!');
      status.textContent = 'Copied!';
    } catch (err) {
      status.textContent = 'Copy failed';
      console.error('Clipboard write failed:', err);
    }
  });
</script>

O await pausa até que a gravação no clipboard seja concluída. Se o usuário tiver negado a permissão ou a página não estiver em um contexto seguro, a promise é rejeitada e o bloco catch é executado — por isso você nunca deve presumir que a cópia foi bem-sucedida.

Lendo Texto do Clipboard

Para ler o texto atual do clipboard, chame navigator.clipboard.readText(). Ele também retorna uma promise, desta vez resolvendo com o conteúdo de texto do clipboard:

<button id="pasteBtn">Read clipboard</button>
<p id="output"></p>
<script>
  const button = document.getElementById('pasteBtn');
  const output = document.getElementById('output');

  button.addEventListener('click', async () => {
    try {
      const text = await navigator.clipboard.readText();
      output.textContent = `Clipboard contains: ${text}`;
    } catch (err) {
      output.textContent = 'Could not read clipboard';
      console.error('Clipboard read failed:', err);
    }
  });
</script>

A leitura é muito mais sensível do que a gravação, pois expõe o que quer que o usuário tenha copiado — possivelmente uma senha ou outros dados privados. Por esse motivo, os navegadores protegem readText() de forma mais rigorosa: exige um gesto explícito do usuário, e alguns navegadores exibem um prompt de permissão na primeira vez, ou permitem leituras apenas quando a aba da página está em foco.

Requisitos e Armadilhas

A Clipboard API tem várias regras que, se ignoradas, levam a rejeições silenciosas. Tenha isso em mente sempre que a utilizar.

Aviso

A Clipboard API só funciona em um contexto seguro — ou seja, HTTPS, ou localhost durante o desenvolvimento. Em uma página http:// simples, navigator.clipboard geralmente é undefined. As chamadas também geralmente exigem um gesto do usuário, como um clique ou pressionamento de tecla, portanto acioná-las no carregamento da página falhará. A Permissions API governa as permissões clipboard-read e clipboard-write, e leituras podem solicitar a confirmação do usuário. Como qualquer chamada pode ser rejeitada — permissão negada, documento sem foco ou navegador sem suporte — sempre envolva as chamadas de clipboard em try...catch.

A página também precisa estar em foco para muitas operações de clipboard. Se você chamar readText() a partir de, por exemplo, um setTimeout enquanto o usuário mudou para outra aba, espere uma rejeição com o erro "document is not focused". Observe também que uma leitura do clipboard só ocorre depois que o usuário tiver focado e interagido com sua página.

Copiando Dados Ricos com ClipboardItem

O texto é o caso simples. Para copiar dados que não sejam texto — imagens, HTML ou vários formatos ao mesmo tempo — use navigator.clipboard.write(), que recebe um array de objetos ClipboardItem. Cada ClipboardItem mapeia tipos MIME para seus dados (tipicamente um Blob).

O exemplo abaixo busca uma imagem, envolve o Blob resultante em um ClipboardItem e o copia:

async function copyImage(url) {
  try {
    const response = await fetch(url);
    const blob = await response.blob();

    const item = new ClipboardItem({ [blob.type]: blob });
    await navigator.clipboard.write([item]);
    console.log('Image copied to clipboard');
  } catch (err) {
    console.error('Failed to copy image:', err);
  }
}

A chave dentro do construtor ClipboardItem é o tipo MIME (aqui blob.type, por exemplo 'image/png'), e o valor são os dados para esse tipo. Um único item pode conter várias representações — por exemplo, tanto 'text/plain' quanto 'text/html' — permitindo que o aplicativo de destino escolha a melhor.

Ler dados ricos espelha isso com navigator.clipboard.read(), que resolve para um array de objetos ClipboardItem que você inspeciona por tipo:

async function readClipboardItems() {
  const items = await navigator.clipboard.read();
  for (const item of items) {
    for (const type of item.types) {
      const blob = await item.getType(type);
      console.log(`Found ${type}`, blob);
    }
  }
}
Nota

O suporte dos navegadores para os métodos de dados ricos (write e read com ClipboardItem) é mais restrito e menos consistente do que para os métodos de texto. Os tipos MIME de imagem, em particular, variam por navegador — image/png é o mais confiável. Faça detecção de funcionalidade com if ('write' in navigator.clipboard) e utilize cópia de texto ou URL como alternativa quando dados ricos não estiverem disponíveis.

O Fallback Legado

Antes da API assíncrona, copiar significava selecionar um elemento e chamar document.execCommand('copy'). Esse método agora está obsoleto, mas ainda funciona em navegadores mais antigos, sendo útil apenas como fallback. O padrão típico selecionava um <textarea> oculto e executava o comando:

function copyTextFallback(text) {
  const textarea = document.createElement('textarea');
  textarea.value = text;
  document.body.appendChild(textarea);
  textarea.select();
  document.execCommand('copy'); // deprecated
  document.body.removeChild(textarea);
}

O código moderno deve preferir a API assíncrona e usar o fallback apenas quando navigator.clipboard não estiver disponível:

async function copyText(text) {
  if (navigator.clipboard) {
    await navigator.clipboard.writeText(text);
  } else {
    copyTextFallback(text);
  }
}

Usos no Mundo Real

A Clipboard API impulsiona muitas interações pequenas, mas valiosas, que você vê todos os dias:

  • Botões "Copiar código" em páginas de documentação, para que os leitores possam pegar um trecho sem precisar selecioná-lo manualmente.
  • Botões "Copiar link para compartilhar" que colocam uma URL no clipboard para colar em chats ou e-mails.
  • Cópia de saída gerada, como uma senha, uma chave de API ou uma citação formatada.
Dica

Seja o que for que você copie, forneça feedback visível. Um botão que copia silenciosamente deixa os usuários em dúvida sobre se funcionou. Troque o rótulo para "Copiado!", exiba um toast breve ou atualize um elemento de status adjacente — isso também é uma melhoria de acessibilidade, já que usuários de leitores de tela não recebem nenhuma indicação do clipboard pelo próprio navegador.

Teste Seus Conhecimentos

Prática
Qual método grava texto no clipboard e retorna uma Promise?
Qual método grava texto no clipboard e retorna uma Promise?
Prática
Por que toda chamada à Clipboard API deve ser envolvida em um bloco try...catch?
Por que toda chamada à Clipboard API deve ser envolvida em um bloco try...catch?
Prática
Quais afirmações sobre a Clipboard API estão corretas?
Quais afirmações sobre a Clipboard API estão corretas?
Was this page helpful?