Agentes geram tabelas com facilidade. O problema aparece quando a grade vira um conjunto de div, os cabeçalhos são apenas células em negrito e o mobile esconde colunas sem explicar o que sumiu. Visualmente, preços e recursos ainda parecem alinhados. Para quem ouve uma célula por vez, números como “49” e “Ilimitado” perdem o contexto.
Uma tabela acessível preserva a relação entre dado, coluna e linha no HTML. Também continua utilizável com zoom, tela estreita, teclado e estilos desativados. Este guia mostra como decidir quando usar uma tabela, marcar estruturas simples e complexas e verificar a versão publicada.
Use tabela apenas quando existe relação tabular
A orientação da W3C sobre tabelas define tabelas de dados como grades que organizam informações por relações lógicas. Cabeçalhos e células precisam de marcação que permita ao navegador determinar essas relações.
Uma comparação de planos, uma agenda por data e uma matriz de compatibilidade podem ser tabulares. Um layout com imagem à esquerda e texto à direita não é. Use CSS Grid ou Flexbox para composição visual.
Faça um teste simples. Escolha uma célula e pergunte quais rótulos ela precisa para ser entendida. Se a resposta é “o nome desta linha e desta coluna”, há uma relação tabular. Se a resposta depende apenas da posição estética, não use <table>.
O guia de HTML semântico ajuda a separar dados de layout. O roteiro de leitor de tela mostra como testar a navegação depois da marcação.
Check 1: identifique a tabela com uma legenda
caption nomeia a tabela e ajuda a pessoa a escolher entre várias grades da página.
<table> <caption> Comparação dos planos mensais </caption> ...</table>A legenda deve dizer o assunto. Não repita “Tabela” nem use uma frase genérica como “Confira abaixo”. Se houver contexto importante, explique-o em texto próximo e relacione a informação quando necessário.
<p id="precos-nota">Valores cobrados por espaço de trabalho, sem impostos.</p><table aria-describedby="precos-nota"> <caption> Comparação dos planos mensais </caption> ...</table>Não esconda uma legenda útil só porque o design já tem um título parecido. Decida qual elemento identifica a grade, evite duplicação e teste o nome que aparece na árvore de acessibilidade.
Check 2: marque cabeçalhos e dados com elementos próprios
Use th para células de cabeçalho e td para dados. strong dentro de td muda o peso visual, mas não cria uma relação programática.
<table> <caption> Limites por plano </caption> <thead> <tr> <th scope="col">Recurso</th> <th scope="col">Inicial</th> <th scope="col">Equipe</th> </tr> </thead> <tbody> <tr> <th scope="row">Sites publicados</th> <td>3</td> <td>20</td> </tr> </tbody></table>Ao chegar ao valor 20, um leitor de tela pode associá-lo a “Sites publicados” e “Equipe”. A cor do fundo não precisa carregar essa tarefa.
Use thead, tbody e tfoot para organizar grupos coerentes. Eles ajudam manutenção e estilo, mas não substituem th e as associações de cabeçalho.
Check 3: declare o escopo quando há linhas e colunas
Em tabelas com cabeçalhos nas duas direções, scope="col" identifica colunas e scope="row" identifica linhas. A técnica H63 da W3C também define colgroup e rowgroup para grupos.
Não aplique scope a todas as células por rotina. Ele pertence aos cabeçalhos e precisa descrever a direção correta.
Verifique:
- todo cabeçalho de coluna usa
the aponta para a coluna certa; - todo rótulo de linha usa
thquando identifica os dados daquela linha; - células vazias não deslocam a associação;
rowspanecolspanrefletem grupos reais;- ordenação e filtros preservam cabeçalhos no DOM.
A orientação da W3C para tabelas com dois cabeçalhos traz o caso comum de uma primeira linha e uma primeira coluna que identificam os dados.
Check 4: simplifique tabelas complexas antes de usar mais ARIA
Uma tabela com cabeçalhos em vários níveis pode exigir grupos ou associações explícitas com id e headers. Antes disso, veja se a informação pode ser dividida em duas tabelas menores.
Grades complexas custam mais para todos:
- o leitor precisa lembrar vários níveis de contexto;
- a versão mobile fica difícil de percorrer;
- filtros e ordenação precisam preservar relações;
- manutenção editorial pode quebrar IDs;
- exportação para outros formatos perde marcação com facilidade.
Quando a complexidade é necessária, cada célula de dados pode indicar os cabeçalhos relevantes:
<th id="grupo-equipe" colspan="2">Equipe</th>...<th id="preco" scope="row">Preço mensal</th>...<td headers="preco grupo-equipe cobranca-anual">R$ 39</td>O valor de headers contém IDs separados por espaço. Cada ID precisa existir e apontar para uma célula de cabeçalho. A técnica H43 da W3C descreve esse vínculo explícito.
Teste com as tecnologias assistivas incluídas no suporte do projeto. Para muitas páginas de marketing, uma estrutura menor com scope é mais robusta do que uma única matriz cheia de cabeçalhos cruzados.
Check 5: escolha uma estratégia mobile que preserve dados
Espremer uma grade larga até o texto ficar ilegível não é responsividade. Remover colunas com display: none também pode esconder a comparação necessária para tomar uma decisão.
Três estratégias costumam funcionar:
- rolagem horizontal dentro de uma região identificada;
- divisão da comparação em tabelas menores;
- transformação em cartões quando cada item continua com todos os rótulos visíveis e programáticos.
Para rolagem, mantenha o foco visível e não prenda o gesto da página:
<div class="table-scroll" role="region" aria-labelledby="planos-caption" tabindex="0"> <table> <caption id="planos-caption"> Comparação dos planos mensais </caption> ... </table></div>Só torne o contêiner focável se isso for necessário para usuários de teclado rolarem a região. Um tabindex extra em toda tabela cria paradas sem benefício. Se usar esse padrão, o foco precisa ser visível e o nome da região deve ser curto.
Teste a 320 pixels CSS e com zoom. O guia de zoom e reflow ajuda a verificar se o contêiner gera rolagem apenas na grade, não na página inteira.
Check 6: preserve significado em ordenação, filtros e estados vazios
Uma tabela interativa adiciona controles. O botão de ordenação precisa ter nome, estado e alvo compreensíveis. Não transforme o texto do cabeçalho em uma div clicável.
<th scope="col" aria-sort="ascending"> <button type="button">Preço</button></th>Quando a ordem muda, atualize aria-sort no cabeçalho ativo e mantenha o foco no controle. Se o filtro reduz os resultados, comunique a quantidade de maneira visível. Mudanças importantes também podem usar uma região de status quando não recebem foco.
O artigo sobre mensagens de erro e status cobre atualizações assíncronas. Para botões de ordenação e filtros, revise também os nomes acessíveis.
Estado vazio não é uma linha de dados falsa. Use uma mensagem fora da grade ou uma linha que preserve a estrutura e deixe claro que nenhum resultado corresponde ao filtro. Não anuncie zeros inventados.
Check 7: não dependa só de um scanner
Automação encontra table sem cabeçalhos, headers com IDs ausentes e alguns usos indevidos de layout. Ela não sabe se “Total” representa uma soma por linha ou por coluna, nem se uma célula mesclada corresponde ao modelo mental do visitante.
Teste uma célula em cada zona da tabela e registre:
| Evidência | Pergunta |
|---|---|
| HTML | th, td, scope, IDs e grupos estão corretos? |
| árvore de acessibilidade | nome, função e relações aparecem? |
| leitor de tela | linha e coluna são anunciadas junto do valor? |
| teclado | rolagem, filtros e ordenação funcionam? |
| tela estreita | todos os dados e rótulos continuam disponíveis? |
Inclua primeira e última célula, uma célula vazia, um grupo e um estado filtrado. Esse recorte é mais útil do que clicar aleatoriamente na grade.
Prompt copiável para o agente
Revise as tabelas de dados deste site sem publicar ainda.
Escopo:- fonte e commit: [referência]- rotas: [lista]- significado de linhas, colunas e grupos: [descrição]
1. Separe tabelas de dados de layouts visuais.2. Registre caption, cabeçalhos, dados, escopos, spans e associações explícitas.3. Simplifique grades complexas quando a divisão preservar melhor o significado.4. Teste uma célula de cada zona com leitor de tela.5. Teste zoom, tela estreita, teclado, filtros, ordenação e estado vazio.6. Preserve valores, unidades, copy, tracking e lógica de negócio.7. Entregue o inventário, as correções e as evidências antes de propor publicação.Não peça apenas “adicione acessibilidade à tabela”. Informe o significado dos dados e exija que o agente prove as relações no HTML final.
Publique a mesma grade que foi aprovada
Tabelas costumam depender de dados ou scripts carregados depois do HTML inicial. Por isso, a validação local não encerra o trabalho.
No Site no Ar, siga o contrato de Publicação: confirme a pasta pública, crie uma nova Version, acompanhe o deploy e abra a URL final. Depois:
- compare valores e unidades com a fonte aprovada;
- confira a tabela antes e depois da hidratação;
- navegue por linha e coluna com leitor de tela;
- teste a largura estreita e o zoom;
- acione ordenação e filtros por teclado;
- confirme que analytics e links continuam corretos.
Se a transformação de build ou o JavaScript remover associações, corrija a fonte e republique o mesmo Site. Uma tabela está pronta quando cada valor mantém seu contexto na URL pública, mesmo sem cor, posição visual ou memória da célula anterior.
