Acessibilidade: para todos, não opcional
A acessibilidade (abreviada a11y: "a", 11 letras, "y") é construir interfaces que qualquer pessoa possa usar, incluídas as que navegam com leitor de tela, só com teclado, ou com baixa visão. Não é um extra: é qualidade de software (e, muitas vezes, um requisito legal).
A boa notícia: 90% da acessibilidade é HTML bem feito.
1) HTML semântico
Use o elemento correto para cada coisa. Um <button> já é focável,
clicável com Enter/Espaço e anunciado como botão; um <div onClick> não é nada
disso.
// ❌ Ruim: um div não é acessível por teclado nem se anuncia como botão
<div onClick={fechar}>Fechar</div>
// ✅ Bom
<button onClick={fechar}>Fechar</button>
O mesmo com <nav>, <main>, <header>, <ul>/<li>, cabeçalhos <h1>…<h6>
em ordem: dão estrutura que as tecnologias assistivas entendem.
2) Rótulos associados aos seus campos
Todo controle de formulário precisa de um rótulo associado. A forma robusta é
<label htmlFor={id}> apontando para o id do campo. No JSX se escreve htmlFor
(não for, que é palavra reservada em JS), mas no DOM real se converte no
atributo for.
<label htmlFor="email">E-mail</label>
<input id="email" type="email" />
Ao associá-los: o leitor de tela anuncia o rótulo ao focar o campo, e clicar no rótulo foca o input (melhor usabilidade para todos).
3) ARIA, só quando faz falta
Os atributos ARIA (aria-*) adicionam informação semântica que o HTML por si
só não expressa. A primeira regra do ARIA é: não use ARIA se um elemento
nativo já faz o trabalho. Mas é muito útil para nuances:
<input aria-required="true" aria-invalid={temErro} />
<button aria-label="Fechar diálogo">✕</button> {/* botão só com um ícone */}
<nav aria-label="Principal">…</nav>
aria-labeldá um nome acessível quando não há texto visível (um botão com só um ícone).aria-required,aria-invalid,aria-expanded… comunicam estado às tecnologias assistivas.
4) Foco e navegação por teclado
Muita gente navega sem mouse. Garanta que:
- Tudo o que é interativo seja focável e operável com teclado (usar
<button>,<a href>, inputs… dá de graça). - A ordem de tabulação siga a ordem visual.
- O foco seja visível (não tire o
outlinesem colocar uma alternativa). - Em componentes complexos (modais, menus) você gerencie o foco com
tabIndex,onKeyDowne, se for preciso, movendo o foco com umaref.
5) IDs únicos com useId
Associar label e input por id tem um problema no React: se o componente é
usado várias vezes na página, um id fixo ("email") se duplicaria, e
os ids devem ser únicos. A solução é o hook useId, que gera um
identificador único e estável (além disso funciona bem com SSR/hidratação):
function Campo({ rotulo }) {
const id = React.useId();
return (
<p>
<label htmlFor={id}>{rotulo}</label>
<input id={id} />
</p>
);
}
Importante:
useIdé para ids de acessibilidade (vincular elementos), não para keys de listas. Reutilize o mesmo id (com sufixos se precisar de vários:${id}-error) para relacionar elementos do mesmo componente.
Nos exercícios deste runtime, use
React.useId()(com o prefixoReact.) para gerar o id.