Um switch bonito pode falhar de um jeito bem básico. A pessoa pressiona Espaço, nada acontece, e o leitor de tela não informa se a opção está ligada. Também pode acontecer o contrário: o controle muda visualmente, mas o valor enviado pelo formulário continua igual.

O problema costuma começar quando um agente recria o controle com uma <div> e concentra todo o esforço na animação. Um switch acessível precisa de semântica, estado, operação por teclado, área de toque e uma regra clara para persistir a escolha.

Este guia ajuda a decidir quando usar switch, checkbox ou botão de alternância e mostra como testar o resultado antes e depois da publicação.

Comece pela decisão que o controle representa

Switches comunicam uma escolha binária com estados “ligado” e “desligado”. Eles combinam com preferências que entram em vigor quando a pessoa altera o controle:

  • receber notificações;
  • ativar o modo escuro;
  • exibir uma camada no mapa;
  • habilitar reprodução automática, quando essa opção for apropriada.

Uma checkbox costuma ser mais clara quando a pessoa seleciona itens para enviar depois, aceita um termo ou monta uma lista. Um botão de alternância serve melhor para uma ação pressionada ou não pressionada, como fixar uma ferramenta na interface.

O padrão de switch da W3C recomenda escolher a função que combina com a linguagem e o comportamento apresentados. Não troque a semântica apenas porque o desenho tem formato de cápsula.

Escreva o contrato antes do código:

Preferência: receber novidades por e-mail
Estados: ligado ou desligado
Estado inicial: desligado
Efeito: salva após confirmação do formulário
Falha: mantém a escolha visível e informa que não foi possível salvar

Essa definição evita que a interface prometa uma alteração imediata enquanto o sistema só envia o valor no botão final.

Prefira um controle HTML nativo

Um input do tipo checkbox já participa do formulário, recebe foco e alterna com Espaço. Você pode estilizar a aparência sem apagar esse comportamento.

<label for="notificacoes">Receber novidades por e-mail</label>
<input id="notificacoes" name="notificacoes" type="checkbox" role="switch" />

O role="switch" apresenta o estado como ligado ou desligado em tecnologias assistivas compatíveis. O próprio checked do input continua sendo a fonte de verdade. Não adicione aria-checked manualmente ao mesmo elemento, pois dois estados controlados separadamente podem divergir.

O HTML também define o atributo experimental switch para checkbox. A documentação do MDN sobre checkbox alerta que o suporte ainda é limitado. Não dependa dele para aparência ou semântica consistente nos navegadores do seu público.

Se uma checkbox comunica a tarefa sem ambiguidade, mantenha a semântica nativa. Acessibilidade não exige que todo controle binário seja anunciado como switch.

Não esconda o input de todas as pessoas

Para desenhar o trilho e o indicador, muita implementação usa display: none no input e deixa uma caixa genérica clicável no lugar. Isso remove o controle da ordem de foco e da árvore de acessibilidade.

Mantenha o input operável. Se a aparência nativa precisar ser substituída, use uma técnica de ocultação visual que preserve foco, clique e semântica. Faça o indicador visual responder a :checked, :focus-visible e :disabled do próprio input.

O rótulo associado aumenta a área clicável. Isso ajuda no toque e evita que a pessoa precise acertar apenas o indicador. O guia sobre tamanho dos alvos de toque traz um roteiro para medir área e separação entre controles.

Não use somente cor ou posição para mostrar o estado. Combine contraste com uma mudança de forma, preenchimento ou indicador. O estado precisa continuar perceptível em alto contraste, escala de cinza e zoom.

Mantenha o mesmo rótulo nos dois estados

O rótulo descreve a preferência. O estado informa se ela está ligada ou desligada.

Use:

Notificações de novidades, switch desligado
Notificações de novidades, switch ligado

Evite trocar “Ativar notificações” por “Desativar notificações” quando o estado muda. A W3C pede que o rótulo do switch permaneça estável. Se o texto muda junto com o estado, a pessoa pode interpretar que recebeu foco em outro controle.

Uma descrição associada pode explicar consequência, custo ou frequência:

<label for="alertas">Alertas de novas mensagens</label>
<p id="alertas-ajuda">Envia uma notificação no navegador quando chegar uma mensagem.</p>
<input id="alertas" name="alertas" type="checkbox" role="switch" aria-describedby="alertas-ajuda" />

Não coloque “ligado” e “desligado” dentro do nome acessível. O leitor de tela já anuncia o estado. Repetir a mesma informação produz frases longas e pode sair de sincronia.

O artigo sobre nomes acessíveis de links e botões ajuda a conferir se texto visível e nome anunciado continuam coerentes.

Decida quando a alteração entra em vigor

Existem dois contratos válidos.

No primeiro, o switch aplica e salva a preferência imediatamente. Nesse caso, a interface precisa lidar com carregamento, sucesso e falha. Não mostre o novo estado como definitivo se a gravação falhou. Reverta o controle ou mantenha a escolha pendente com uma mensagem clara.

No segundo, o switch faz parte de um formulário. A alteração só vale depois de “Salvar preferências” ou outro botão explícito. Não anuncie sucesso ao alternar o controle. O envio final é que confirma a persistência.

Checkboxes desmarcadas não entram nos dados enviados por um formulário HTML. Se o serviço exige um valor explícito, trate a ausência no servidor ou envie uma representação definida pelo contrato. Não invente essa regra no componente.

Quando houver resposta assíncrona, use o roteiro de mensagens de erro e status acessíveis. Um erro útil informa o que não foi salvo e permite tentar de novo sem perder o restante do formulário.

Agrupe preferências relacionadas

Uma lista de switches precisa de um nome para o conjunto. fieldset e legend resolvem essa relação no HTML:

<fieldset>
<legend>Notificações</legend>
<label for="mensagens">Novas mensagens</label>
<input id="mensagens" name="mensagens" type="checkbox" role="switch" />
<label for="resumo">Resumo semanal</label>
<input id="resumo" name="resumo" type="checkbox" role="switch" />
</fieldset>

Cada switch ainda precisa de rótulo próprio. A legenda informa o contexto comum. Não use um único aria-label genérico em todos os controles.

Se uma preferência controla a disponibilidade de outra, deixe a relação explícita. Desabilite o controle dependente apenas quando ele realmente não pode ser alterado. Explique a condição em texto e garanta que a sequência de foco continue previsível.

Teste comportamento, estado e persistência

Ver a cápsula se mover não prova que o controle funciona. Faça uma matriz curta:

Cenário Resultado esperado
foco com Tab indicador de foco fica visível
ativação com Espaço estado muda uma vez e a página não rola
clique no rótulo o mesmo controle é alternado
leitor de tela nome, função e estado fazem sentido
alto contraste foco e estado continuam distinguíveis
zoom e reflow rótulo não cobre o indicador nem perde associação
toque toda a área planejada responde sem atingir o controle vizinho
envio do formulário servidor recebe o valor previsto para os dois estados
falha ao salvar escolha não finge sucesso e a mensagem permite nova tentativa
recarregamento preferência exibida corresponde ao valor realmente persistido

Use o guia de teste com leitor de tela para registrar navegador, tecnologia assistiva, versão e tarefa. Teste também o controle sem CSS e com JavaScript indisponível quando a escolha fizer parte de um formulário essencial.

Dê ao agente um pedido verificável

Um prompt preciso separa semântica, regra de persistência e evidência:

Revise os controles de preferências desta landing page.
Use switch apenas para escolhas binárias descritas como ligado ou desligado.
Mantenha o mesmo rótulo nos dois estados.
Prefira input type="checkbox" e preserve o comportamento nativo.
Confirme foco visível, ativação com Espaço, área de toque,
alto contraste, zoom, leitor de tela e valor enviado.
Explique quando cada escolha é salva e simule uma falha de persistência.
Não publique antes de apresentar os resultados.

O agente pode corrigir o código e executar testes automatizados. A decisão sobre consentimento, valor inicial e momento da gravação pertence ao produto.

Reteste a URL publicada

Depois das correções, gere os arquivos públicos e faça uma última inspeção no ambiente final. No Site no Ar, o agente mantém a saída em public/, chama deploy e acompanha deploy_status até um estado terminal, conforme o guia de Publicação.

Na URL publicada:

  1. percorra todos os switches só com teclado;
  2. confira nome, função e estado com leitor de tela;
  3. altere cada preferência e confirme o valor recebido;
  4. force uma falha autorizada e observe a recuperação;
  5. recarregue a página e verifique o estado persistido;
  6. repita em largura pequena, zoom e dispositivo de toque.

Um switch acessível não é uma checkbox escondida atrás de uma animação. É uma escolha binária cujo rótulo permanece estável, cujo estado chega a todas as pessoas e cujo valor sobrevive ao caminho completo até o servidor.