Um upload pode funcionar no mouse e falhar no resto. A área de arrastar arquivos não recebe foco, o limite aparece só depois do erro, o progresso muda sem anúncio e o botão “Remover” não diz qual arquivo será excluído. Em uma landing page criada por IA, esses problemas surgem quando o componente visual substitui o campo nativo antes de definir o contrato do envio.

Comece por input type="file". Ele abre o seletor do sistema, participa do formulário e já oferece comportamento conhecido. Arrastar e soltar, pré-visualização e envio assíncrono podem melhorar a tarefa, mas precisam complementar esse caminho.

Escreva as regras antes do componente

Defina o que o destino aceita:

Finalidade: anexar comprovante de residência
Quantidade: 1 arquivo
Formatos aceitos: PDF, JPG e PNG
Tamanho máximo: 10 MB
Validação final: serviço que recebe o formulário
Retenção: conforme a política informada ao usuário

Não peça “imagem” se o processo também aceita PDF. Não diga “até 10 MB” e aplique outro limite no servidor. Se o arquivo contém dados pessoais, explique finalidade e retenção perto do campo ou em uma política acessível antes do envio.

O agente não deve inventar formatos, tamanho ou política de armazenamento. Essas regras pertencem ao produto e precisam ser iguais na instrução, no código e na validação do serviço.

Mantenha o campo nativo no caminho principal

Uma base pequena resolve a seleção:

<label for="comprovante">Comprovante de residência</label>
<p id="comprovante-ajuda">Envie um arquivo PDF, JPG ou PNG de até 10 MB.</p>
<input
id="comprovante"
name="comprovante"
type="file"
accept=".pdf,.jpg,.jpeg,.png,application/pdf,image/jpeg,image/png"
aria-describedby="comprovante-ajuda"
/>

O MDN documenta input type="file" como o controle que permite escolher um ou mais arquivos do dispositivo. Use multiple somente quando o fluxo aceita mais de um arquivo.

Se o visual exige um botão próprio, associe um label ao input e oculte o controle sem removê-lo da árvore de acessibilidade. display: none e visibility: hidden tornam o input não interativo para tecnologias assistivas. Teste a técnica escolhida com teclado, modo de alto contraste e leitor de tela.

Não dependa de um clique programático num elemento genérico. O campo e o rótulo fornecem uma base mais resistente a diferenças entre navegadores e dispositivos.

Trate accept como orientação, não segurança

O atributo accept restringe as opções mostradas pelo seletor, mas não valida o arquivo. O MDN sobre accept explica que a pessoa pode conseguir substituir o filtro do seletor. Valide extensão, tipo, conteúdo e tamanho no serviço que recebe o upload.

Liste extensões e tipos MIME quando isso ajudar a cobrir variações do sistema. Ainda assim, não confie no File.type enviado pelo navegador como prova do conteúdo. Uma mensagem útil informa o arquivo, a regra violada e a correção possível:

"conta-heic.heic" não foi enviado. Escolha PDF, JPG ou PNG de até 10 MB.

Não apague os outros campos do formulário por causa desse erro. Se houver vários arquivos, preserve os válidos e identifique apenas os rejeitados quando o contrato permitir reenvio parcial.

Faça de arrastar e soltar um atalho opcional

Uma área de drop não substitui o seletor. Pessoas que usam teclado, comando de voz ou dispositivos sem gesto de arrastar precisam de um botão visível para escolher arquivos.

Use um texto direto:

Arraste o arquivo para esta área ou escolha no dispositivo.

O botão ou rótulo abre o mesmo input type="file". A área visual pode reagir durante o arrasto, mas não deve exigir precisão fina. Não use só mudança de cor para indicar que o arquivo pode ser solto.

Se a área inteira for interativa, evite criar dois focos com a mesma ação. Um único controle claro costuma ser melhor que uma caixa clicável e um botão interno competindo na ordem de teclado.

Mostre os arquivos escolhidos como dados, não decoração

Depois da seleção, apresente nome, tamanho e estado. Para vários arquivos, use uma lista:

<ul aria-label="Arquivos selecionados">
<li>
contrato.pdf, 2,4 MB
<button type="button" aria-label="Remover contrato.pdf">Remover</button>
</li>
</ul>

O texto visível pode dizer “Remover”, mas o nome acessível precisa identificar o arquivo. Se dois botões iguais aparecem na lista sem contexto, a pessoa que navega por controles ou comando de voz não sabe qual acionar.

Para imagens, uma miniatura não substitui o nome do arquivo e o estado. Também não transforme a prévia em texto alternativo inventado. Se a imagem será publicada com conteúdo, peça uma descrição num campo separado e explique a finalidade.

O artigo sobre nomes acessíveis de links e botões ajuda a revisar ações repetidas em listas.

Separe seleção, envio e confirmação

Escolher um arquivo não significa que o servidor o recebeu. Mostre os estados reais:

selecionado -> enviando -> processando -> concluído
-> falhou

Se o formulário envia tudo ao final, diga que o arquivo está selecionado. Não anuncie “enviado” antes da resposta do servidor. Se o upload começa logo após a seleção, ofereça cancelamento quando ele tiver efeito real e deixe claro o que acontece com um arquivo parcialmente transferido.

Uma mensagem breve de sucesso pode usar uma região de status. Uma falha que exige decisão precisa continuar visível junto ao arquivo e oferecer uma nova tentativa. A WCAG 2.2 sobre mensagens de status inclui progresso, espera, sucesso, resultado e erro apresentados sem mover o foco.

Evite regiões vivas que anunciam cada variação de 1%. Para um envio longo, anuncie marcos úteis ou use um indicador de progresso com valor programático. A pessoa precisa saber que o processo continua, não ouvir uma sequência ininterrupta de números.

Preserve foco e contexto ao remover ou reenviar

Quando a pessoa remove um arquivo, coloque o foco no próximo controle lógico. Pode ser o botão de remoção do arquivo seguinte, a lista atualizada ou o campo para escolher outro arquivo. Não devolva o foco ao início da página.

Ao tentar de novo, mantenha a mensagem de falha disponível até a nova resposta. Se o arquivo precisa ser escolhido novamente por uma limitação de segurança ou sessão, diga isso. Scripts não podem preencher um campo de arquivo com um caminho local em nome da pessoa.

Use o roteiro de mensagens de erro e status acessíveis para ligar cada falha ao arquivo e anunciar mudanças sem interromper a tarefa.

Não deixe segurança e privacidade só no texto

O serviço deve impor quantidade, tamanho e formatos. Renomeie ou isole arquivos conforme a arquitetura, não execute conteúdo enviado e não exponha o caminho local. A interface do navegador mostra um caminho fictício para evitar revelar a estrutura do dispositivo.

Se o upload contém documentos pessoais:

  • use conexão segura;
  • limite quem pode acessar o arquivo;
  • defina retenção e exclusão;
  • não registre conteúdo ou nomes sensíveis sem necessidade;
  • explique a finalidade antes do envio.

Acessibilidade não reduz essas obrigações. Um erro detalhado precisa orientar a correção sem revelar regras internas que facilitem abuso.

Teste seleção, transferência e recuperação

Uma matriz mínima cobre o caminho completo:

Cenário Resultado esperado
teclado abre o seletor e alcança remover, cancelar e reenviar
leitor de tela rótulo, instruções, arquivos e estados fazem sentido
formato inválido arquivo é identificado e a regra correta é informada
tamanho excedido erro aparece antes ou depois do envio sem apagar o formulário
vários arquivos quantidade, lista e ações correspondem a cada item
conexão lenta progresso útil é visível e anunciado sem excesso
falha de rede estado não finge sucesso e oferece nova tentativa
remoção item some e o foco vai para um destino lógico
zoom e largura pequena nomes longos não cobrem botões nem mensagens
validação do servidor arquivo renomeado ou adulterado continua rejeitado

Teste com nome longo, extensão em maiúsculas, arquivo vazio, limite exato, um byte acima do limite e seleção cancelada. Para vários arquivos, misture itens válidos e inválidos e confirme a política de tratamento.

O guia de teste de formulários ajuda a cobrir rótulos, instruções, erros, preservação de dados e resposta do destino.

Dê ao agente critérios que possam falhar

Um prompt específico evita um componente que só funciona na demonstração:

Revise o upload de comprovante desta landing page.
Aceite um arquivo PDF, JPG ou PNG de até 10 MB.
Mantenha input type="file" e um botão visível para escolher o arquivo.
Trate arrastar e soltar apenas como atalho.
Mostre nome, tamanho e estado real do arquivo.
Valide novamente no servidor.
Teste teclado, leitor de tela, zoom, conexão lenta, falha e reenvio.
Não publique antes de apresentar as evidências e a política de retenção.

O agente pode implementar o campo, simular respostas e organizar os resultados. A finalidade, os formatos aceitos, o limite e a retenção precisam vir do produto.

Reteste depois da publicação

O build e o domínio final podem mudar cabeçalhos, tamanho máximo da requisição, timeout e comportamento do serviço. No Site no Ar, mantenha os arquivos públicos em public/, execute deploy e acompanhe deploy_status até o estado terminal, conforme o guia de Publicação.

Na URL publicada:

  1. escolha um arquivo pelo teclado;
  2. repita por toque e, se existir, arrastar e soltar;
  3. teste formatos válidos, inválidos e o limite de tamanho;
  4. observe progresso com leitor de tela;
  5. interrompa a conexão e tente de novo;
  6. remova um arquivo e acompanhe o foco;
  7. confirme no destino o arquivo recebido e o estado final.

Um upload acessível não termina quando o seletor abre. A pessoa precisa entender a regra, escolher o arquivo por mais de um caminho, acompanhar o envio e se recuperar de uma falha sem perder o restante do formulário.