10 pontos por GN⁺ 2025-11-02 | 7 comentários | Compartilhar no WhatsApp
  • Na interface web, usar <button> em vez de <div> é a escolha correta em termos de acessibilidade e funcionalidade
  • Um <div> não é reconhecido por leitores de tela como um elemento interativo e também não responde a foco do teclado nem às teclas Enter e Spacebar
  • Mesmo adicionando os atributos [role="button"] ou [tabindex="0"], continuam existindo problemas na ordem de foco e no tratamento de eventos de teclado
  • Para resolver isso, adicionar vários event listeners e condicionais gera uma complexidade desnecessária
  • Como o <button> já oferece por padrão acessibilidade, foco e tratamento de entrada via teclado, ele é a solução mais simples e padronizada

Abordagem errada: criar um botão com <div>

  • Entre usuários de React ou HTMX, é comum ver casos em que interações como abrir um modal são implementadas com <div onclick="...">
    • Exemplo de código:
      <div onclick="showSignIn()">Open Modal</div>
      
  • Problemas dessa abordagem
    • Leitores de tela não reconhecem esse elemento como interativo
    • Não é possível mover o foco pelo teclado até ele
    • Apenas o evento click funciona, e as teclas Enter e Spacebar não disparam a ação

Limites das tentativas de “corrigir” a acessibilidade

  • Ao adicionar o atributo [role="button"], o problema de reconhecimento pelos leitores de tela é resolvido, mas
    os problemas de foco e de tratamento de entrada pelo teclado continuam
  • É possível permitir foco adicionando [tabindex="0"], mas
    há risco de bagunçar a ordem de foco ou causar movimentações inesperadas
  • Para tratar entrada pelo teclado, seria necessário registrar o evento keydown globalmente (document) e
    detectar as teclas Enter ou ' ' (espaço) para encontrar o elemento focado e executá-lo
    document.addEventListener('keydown', (event) => {
      if (event.key !== 'Enter' && event.key !== ' ') return;
      const notRealBtn = document.activeElement.closest('[onclick]');
      if (!notRealBtn) return;
      // 실행 코드
    });
    
  • No fim, isso significa reimplementar de forma complexa funcionalidades que o <button> já fornece por padrão

Funcionalidades nativas que o <button> oferece

  • O elemento <button> já oferece automaticamente o seguinte:
    • papel implícito ([role="button"])
    • capacidade automática de receber foco
    • com foco, disparo do evento click ao pressionar Enter ou Spacebar
  • Para implementar o mesmo comportamento com <div>, seriam necessários vários atributos e scripts, enquanto
    com <button> tudo se resolve em uma única linha
    <button onclick="showSignIn()">Open Modal</button>
    

Conclusão: simplicidade é o melhor caminho

  • O <button> é a forma mais simples de atender aos padrões de acessibilidade e ainda reduzir a quantidade de código
  • Sem tratamento desnecessário de eventos nem adição de atributos, usar elementos HTML padrão é melhor para manutenção e eficiência
  • Com a mensagem de que “quanto mais preguiçoso o desenvolvedor, mais ele deve usar o elemento correto”, o texto
    destaca a importância de hábitos de desenvolvimento que evitam complexidade desnecessária e aproveitam funcionalidades nativas

7 comentários

 
come2mecome 2025-11-04

Texto muito bom. A ideia principal do conteúdo pode ser resumida como: "vamos usar as tags HTML com significado". Se você oferece um evento de clique com uma tag div (ou outra qualquer), acho que não mudou absolutamente nada em relação à época em que o layout era montado com tags table.

 
carnoxen 2025-11-11

Claro, colocar atributos aria-* pode deixar isso mais claro, mas já que vai dar esse trabalho todo, é melhor simplesmente usar a tag apropriada kkkkk

 
roxie 2025-11-06

Que nostalgia kkk

 
carnoxen 2025-11-02

Os sites de órgãos públicos aqui no país usam muito &lt;a&gt;...

 
GN⁺ 2025-11-02
Opinião do Hacker News
  • Uma das minhas reclamações é quando sites implementam navegação com handlers onclick
    É só usar a tag <a> e tudo já funciona automaticamente: abrir em nova aba, integração com recursos de acessibilidade, menu de clique direito etc.
    Se é navegação, use links em vez de uma sopa de JavaScript

    • Nos últimos anos, esse tipo de implementação ficou mais comum
      Provavelmente por influência de frameworks ou simples descuido
      Ainda assim, a forma tradicional quase sempre é melhor em termos de UX
      Espero que haja pelo menos um pouco de atrito para quem tenta substituir a tag <a>
    • Acho que o problema é que desenvolvedores que começaram com React pularam direto para a “parte divertida” sem aprender os conceitos básicos de HTML
      Esse pessoal cria padrões errados e os desenvolvedores seguintes acabam copiando
      Foram raríssimas as vezes em que precisei estilizar uma <div> para parecer um botão
    • Também precisamos acabar com rolagem baseada em JS
      Eu uso bastante o botão do meio do mouse para rolar, e muitos sites quebram isso
    • Isso me faz lembrar do verificador de links do Microsoft Office 365
      Se clicar com o botão esquerdo, abre uma página de verificação de segurança; se clicar com o do meio, vai direto
    • Num projeto recente em React do qual participei, toda a navegação era feita com onClick
      Até elementos que na prática eram links eram tratados inteiramente com handlers de clique, o que não faz sentido para mim
  • Na maioria dos botões, é preciso explicitar type="button"
    O padrão é submit, então, se estiver dentro de um formulário, ele envia automaticamente
    Acho que alguns desenvolvedores não sabem disso e por isso acabam usando <div>

    • Acho que esse ponto principal ficou faltando no texto longo do OP
      Botões com o tipo padrão se comportam de forma estranha e às vezes até ignoram handlers de JS
    • O padrão corresponde a <input type="submit">, e <button> é diferente
    • Eu também aprendi isso na prática
    • Usar <div> evita o problema de type="submit"
      Uma <div> começa vazia, então você só adiciona o comportamento de que precisa e depois também é mais fácil mudar
      Já com <button>, você precisa consultar a documentação para entender o comportamento padrão
      No fim, é uma escolha entre controle explícito vs funcionalidade embutida
  • Eu gostaria que o texto fosse ampliado para a ideia de “usar os elementos HTML feitos para aquele propósito”
    Muitos desenvolvedores de SPA não entendem bem a semântica dos elementos HTML e acabam reinventando a roda o tempo todo

    • Seria bom se os elementos fossem mais estilizáveis
      Por exemplo, o date picker padrão é tão feio que as pessoas acabam substituindo por versões em JS
    • A ideia de “usar a plataforma como ela é” aparece bastante no frontend desde o HTML5, mas ainda não se espalhou por toda parte
    • Na prática, a maioria dos desenvolvedores quase não conhece os elementos HTML e quer resolver tudo com uma DIV
    • Por volta de 2010, cada navegador tinha um estilo diferente para botões, então era preciso fazer na mão
      Esse é um dos contextos em que surgiram os botões customizados
  • Hoje existe uma geração que fica clicando pela tela inteira tentando descobrir o que é clicável
    Uns 10 anos atrás, alguém tornou arrastar links mais importante do que selecionar texto, e agora selecionar texto ficou quase impossível
    Talvez seja preciso fazer um fork do navegador para corrigir isso

    • Eu tenho o hábito de arrastar links para abrir em abas em segundo plano
      Se você segurar Alt (ou Option), dá para selecionar o texto dentro do link
    • No iOS, tentar copiar um número de telefone e acabar ligando automaticamente é um incômodo parecido
      É um comportamento realmente indesejado
    • Texto que não pode ser selecionado me deixa maluco
      No macOS, o app TextSniper permite selecionar uma área e copiar o texto com OCR
      Graças a isso, até o Google Analytics fica um pouco mais utilizável
    • Eu também vivo tentando selecionar parte do texto dentro de links e fracassando
      Esse problema deveria ser mencionado com mais frequência
    • Também existem extensões de navegador para selecionar texto de links
      Antigamente havia a Select Like A Boss; hoje é a Drag-Select Link Text
  • Fiquei muito tempo quebrando a cabeça com um bug de tamanho no flexbox por causa de button {align-items: flex-start} na stylesheet padrão do Chrome
    Ainda assim, tento usar os elementos HTML corretos sempre que possível, embora em projetos paralelos pequenos às vezes seja mais prático usar <div>

    • A propriedade appearance: none é útil para resetar o estilo de botões
      Eu criei uma classe .unbuttonify para algo que se comporta como botão, mas tem outra aparência
    • Também quero reforçar que desenvolvedores frontend precisam conhecer o básico de CSS
  • Sempre que possível, os elementos devem ser usados conforme a intenção original

  • Tenho duas reclamações sobre botões
    Uma é que no fim você quase sempre precisa reestilizá-los,
    e a outra é o aviso de que botões não podem ser aninhados
    Na prática, isso aparece com bastante frequência

  • LLMs frequentemente geram esses padrões errados
    Muitas vezes ignoram os recursos nativos do navegador e implementam tudo de forma complexa
    Eu costumo pedir ao Claude para simplificar esse tipo de código
    No TypeScript, também tendem a inventar formas estranhas de lidar com erros

    • LLMs são muito boas em escrever código, mas têm pouco senso de engenharia de software
    • Pela própria natureza de prever tokens, LLMs tendem a escolher padrões mais complexos com mais frequência
  • Eu tento usar botões como padrão sempre que possível
    Mas, quando algo de fato deve funcionar como link, uso a tag <a>

    • Se a URL muda, eu trato como link; se não muda, como botão
    • Se é um “hiperlink que navega dentro do webapp”, então é uma tag <a>
  • Fiquei curioso sobre por que alguém defenderia usar <div>

    • Provavelmente porque <div> facilita umas customizações visuais estranhas
      E aí o resultado acaba não parecendo nem se comportando como botão
    • Por exemplo, sites como o TV Tropes implementavam listas longas em formato de “pastas” expansíveis com <div onclick>
    • O motivo mais comum é preguiça de sobrescrever o estilo padrão do botão
 
nemorize 2025-11-02

background, border, outline, appearance, -webkit-appearance, cursor
Há estilos padrão demais que precisam ser sobrescritos T_T

 
rtyu1120 2025-11-03

É por isso que existe o CSS Reset.