O que é ARIA?

ARIA (Accessible Rich Internet Applications) é uma especificação W3C que permite melhorar a acessibilidade de aplicações web ricas e componentes dinâmicos.

🏷️ Papéis

Define o que um elemento é (botão, navegação, alerta...)

role="button"

📊 Estados

Descrevem o estado atual de um elemento (marcado, expandido, desabilitado...)

aria-expanded="true"

🔧 Propriedades

Fornecem informações adicionais (rótulo, describedby, controls...)

aria-label="Menu principal"

⚠️ Regra de Ouro do ARIA

Não use ARIA se você pode usar HTML nativo

Formulários com atributos ARIA

Exemplo ruim

Formulário sem ARIA

❌ Formulário inacessível sem atributos ARIA apropriados:

<!-- Ruim: sem rótulo, sem descrição -->
<input type="text" placeholder="Seu e-mail">

<!-- Ruim: ícone não acessível -->
<button>
  <span class="icon">🔍</span>
</button>

<!-- Ruim: erro não associado, sem autocompletar -->
<input type="password">
<div class="error">Senha muito curta</div>
Senha muito curta
Eu aceito os termos de uso

Exemplo bom

Formulário com ARIA

✅ Formulário acessível com atributos ARIA apropriados:

<!-- Bom: aria-label para campo sem rótulo visível -->
<input
  type="text"
  aria-label="Endereço de e-mail (obrigatório)"
  aria-describedby="email-desc"
  aria-required="true">
<span id="email-desc">Formato: nome@exemplo.com</span>

<!-- Bom: botão com aria-label -->
<button aria-label="Enviar formulário">
  <span aria-hidden="true">🔍</span>
</button>

<!-- Bom: erro associado com aria-describedby -->
<input
  type="password"
  aria-label="Senha (mínimo de 8 caracteres)"
  aria-invalid="true"
  aria-describedby="pwd-error"
  autocomplete="new-password">
<div id="pwd-error" role="alert">
  Senha deve conter pelo menos 8 caracteres
</div>
Formato: nome@exemplo.com
Mínimo de 8 caracteres com números e letras
Opções de notificação
Receber atualizações importantes por e-mail
Receber alertas urgentes por SMS
Atributos ARIA utilizados:
  • aria-label: Fornece um rótulo acessível
  • aria-describedby: Associa uma descrição detalhada
  • aria-required: Indica um campo obrigatório
  • aria-invalid: Sinaliza um campo inválido
  • aria-labelledby: Referencia um rótulo existente
  • role="alert": Anuncia erros imediatamente
  • aria-hidden: Oculta elementos decorativos
  • aria-live: Anuncia mudanças dinâmicas

Explicação: Atributos ARIA enriquecem formulários fornecendo rótulos, descrições e estados para tecnologias assistivas.

Accordion acessível

Exemplo ruim

Sem atributos ARIA

O que é acessibilidade web?+
Por que é importante?+
Como começar?+
<!-- Ruim: Sem atributos ARIA, sem navegação por teclado -->
<div class="accordion-header" @click="toggle">
  <span>Title</span>
  <span>+</span>
</div>
<div v-if="open">
  Content
</div>

Exemplo bom

Com ARIA adequado

<!-- Bom: ARIA completo com navegação por teclado -->
<button
  id="accordion-button-1"
  aria-expanded="false"
  aria-controls="panel-1"
  @click="toggle"
  @keydown.enter="toggle"
>
  Title
</button>
<div
  id="panel-1"
  role="region"
  aria-labelledby="accordion-button-1"
  :hidden="!open"
>
  Content
</div>

Explicação: Um accordion deve usar atributos ARIA apropriados, suportar navegação por teclado e anunciar mudanças de estado.

Tabindex e navegação por teclado

O atributo tabindex controla se um elemento pode receber foco do teclado e em que ordem.

✅ tabindex="0"

Elemento é focalizável na ordem natural do DOM

tabindex="0"
<!-- Bom: Elemento interativo focalizável -->
<div role="button" aria-label="Custom action" tabindex="0">
  Custom button
</div>

⚠️ tabindex="-1"

Focalizável por JavaScript, mas não por Tab

tabindex="-1"
<!-- Bom: Para foco programático -->
<div role="alert" aria-live="assertive" tabindex="-1">
  Error message
</div>

❌ tabindex > 0

Altera a ordem de navegação (evite!)

tabindex="5"
<!-- Ruim: Quebra a ordem natural de tabulação -->
<button tabindex="3">Third</button>
<button tabindex="1">First</button>
<button tabindex="2">Second</button>

📋 Tabindex best practices

  • Use tabindex="0" para tornar elementos interativos personalizados focalizáveis
  • Use tabindex="-1" para foco programático (modais, alertas)
  • NUNCA use valores positivos - respeite a ordem do DOM
  • Elementos interativos nativos (<button>, <a>, <input>) não precisam de tabindex

🎯 Interactive examples

Teste a navegação por teclado (Tab/Shift+Tab) com estes elementos:

✅ Focusable elements

Link
Botão personalizado (div)

❌ Elementos não focalizáveis

Texto simples (div)
Texto em linha (span)

Parágrafo

💡 Testing tips

  • Use Tab para navegar para frente
  • Use Shift + Tab para navegar para trás
  • Use Espaço ou Enter para ativar elementos
  • Observe o indicador de foco (contorno azul)
  • Observe quais elementos podem ou não receber foco

Menu suspenso acessível

Exemplo ruim

Exemplo bom

Explicação: A dropdown menu must support keyboard navigation, close with Escape, and maintain focus appropriately.

Galeria de imagens acessível

Exemplo ruim

Exemplo bom

Explicação: An image gallery must allow keyboard navigation and provide contextual descriptions for each image. The ARIA tablist/tab/tabpanel pattern is perfect for this use case.

Tabela ordenável acessível

Exemplo ruim

Nome ↑E-mail Função Status
Alice Martinalice@example.comAdministradorAtivo
Bob Dupontbob@example.comUsuárioInativo
Charlie Leroycharlie@example.comModeradorAtivo
Diana Moreaudiana@example.comUsuárioSuspenso

Exemplo bom

Alice Martinalice@example.comAdministradorAtivo
Bob Dupontbob@example.comUsuárioInativo
Charlie Leroycharlie@example.comModeradorAtivo
Diana Moreaudiana@example.comUsuárioSuspenso
Clique nos cabeçalhos das colunas para ordenar a tabela. Use Tab para navegar entre os botões de ordenação.

Explicação: A sortable table must indicate the current sort state, allow keyboard navigation, and announce changes to screen readers.

Regiões aria-live dinâmicas

Exemplo ruim

Sem aria-live

Mudanças não são anunciadas

<!-- Mauvais : pas d'attribut aria-live -->
<div class="status-banner">
  <p></p>
</div>

Contador: 0

Problemas:

  • Mudanças não são anunciadas
  • Usuários de leitores de tela não sabem que o conteúdo mudou
  • Sem indicação da importância da mensagem

Exemplo bom

Com aria-live apropriado

Mudanças são anunciadas de acordo com sua prioridade

<!-- Bon : avec aria-live="polite" pour informations -->
<div
  class="status-banner"
  aria-live="polite"
  aria-atomic="true"
  role="status"
>
  <p>Information : Données mises à jour</p>
</div>

<!-- Bon : avec aria-live="assertive" pour alertes -->
<div
  class="alert-banner"
  aria-live="assertive"
  aria-atomic="true"
  role="alert"
>
  <p>Attention : Action requise immédiatement</p>
</div>

Zona educada (informação)

Vantagens:

  • Mensagens importantes interrompem com aria-live="assertive"
  • Mensagens informativas aguardam com aria-live="polite"
  • aria-atomic="true" anuncia todo o conteúdo da região
  • Papéis apropriados (status, alert) fornecem mais contexto

Explicação: Aria-live regions allow announcing content changes to screen readers. 'polite' waits for the current announcement to finish, 'assertive' interrupts immediately.

Botões de ícone acessíveis

Exemplo ruim

Botões sem descrição

Estes botões não têm indicação de texto:

Problemas:
  • Leitores de tela apenas anunciam "botão"
  • Impossível saber a ação sem ver o ícone
  • Emojis podem ser mal interpretados
  • Sem dica ao passar o mouse

Exemplo bom

Botões acessíveis

Várias abordagens para tornar ícones acessíveis:

1. Com aria-label
2. Com texto visível
3. Com texto visualmente oculto
Melhores práticas:
  • Sempre forneça texto alternativo (aria-label, texto oculto ou texto visível)
  • Use aria-hidden="true" em ícones decorativos
  • Adicione dicas com o atributo title
  • Prefira texto visível quando o espaço permitir

Explicação: Buttons that contain only icons must have an aria-label or visually hidden text to be understood by screen readers.

Combobox / Pesquisa com sugestões

Exemplo ruim

Sem ARIA ou navegação por teclado

Exemplo bom

Com ARIA e navegação por teclado

0 resultado(s) disponível(is)

Explicação: A search with suggestions (combobox) must be keyboard navigable, announce results and allow selection.

Notificações toast (Regiões dinâmicas)

Exemplo ruim

Sem aria-live

❌ Notificações não são anunciadas para leitores de tela

<!-- Ruim: não anunciado para leitores de tela -->
<div v-if="showToast" class="toast">
  Votre demande a été enregistrée
</div>

Exemplo bom

Com aria-live apropriado

✅ Notificações são devidamente anunciadas

<!-- Bom: notificação informativa (educado) -->
<div
  v-if="showToast"
  role="status"
  aria-live="polite"
  aria-atomic="true"
  class="toast"
>
  <p>Votre demande a été enregistrée</p>
  <button @click="dismiss" aria-label="Fermer notification">✕</button>
</div>

<!-- Bom: alerta de erro (assertivo) -->
<div
  v-if="showError"
  role="alert"
  aria-live="assertive"
  aria-atomic="true"
  class="toast error"
>
  <p>Erreur : action impossible à exécuter</p>
  <button @click="dismiss" aria-label="Fermer alerte">✕</button>
</div>
Diferenças:
  • role="status" + aria-live="polite": Para notificações informativas, não interrompe a leitura atual
  • role="alert" + aria-live="assertive": Para erros críticos, interrompe imediatamente
  • aria-atomic="true": Anuncia todo o conteúdo da notificação

Explicação: Dynamic notifications must be announced to screen readers without stealing focus. Use role='status' for info and role='alert' for errors.