Escolher uma data parece uma tarefa pequena até o calendário exigir dezenas de Tab, esconder o mês atual do leitor de tela ou rejeitar uma data sem explicar o formato aceito. Em landing pages criadas por IA, o problema costuma surgir quando um calendário personalizado substitui um campo nativo apenas para reproduzir um mockup.
Um seletor de data reúne entrada de texto, validação, navegação por calendário, localização e regras do negócio. Se uma dessas partes fica implícita, a pessoa pode enxergar a data certa e ainda enviar o valor errado.
Este guia começa pelo controle mais simples e mostra o que precisa ser implementado e testado quando um calendário próprio for realmente necessário.
Defina a data que o formulário pede
Antes do componente, escreva a regra:
Campo: data da visitaPrecisão: dia, mês e anoFuso relevante: America/Sao_PauloPrimeira data permitida: amanhãÚltima data permitida: 90 dias a partir de hojeDias indisponíveis: domingos e feriados cadastradosFormato exibido: dd/mm/aaaaValor enviado: yyyy-mm-ddNem toda escolha é uma data civil simples. Um evento com hora precisa declarar fuso. Uma reserva pode depender da unidade escolhida. Uma data de nascimento não deve bloquear anos anteriores por causa de um limite copiado de outro campo.
Não deixe o agente inferir essas regras pelo texto da página. Elas pertencem ao produto e precisam aparecer na validação, nas instruções e nos testes.
Comece com o controle nativo
Para dia, mês e ano, teste primeiro:
<label for="data-visita">Data da visita</label><input id="data-visita" name="dataVisita" type="date" min="2026-09-21" max="2026-12-19" />O input type="date" documentado pelo MDN usa uma interface fornecida pelo navegador e pelo sistema. A apresentação varia conforme o dispositivo e a localidade. O valor enviado, porém, segue yyyy-mm-dd.
Essa diferença é útil. A pessoa vê um formato familiar, enquanto o sistema recebe uma representação previsível. Não transforme o valor em meia-noite UTC apenas para armazená-lo. Uma data civil sem horário não é um instante. A conversão descuidada pode deslocar o dia quando o fuso muda.
Use min e max quando os limites forem conhecidos. Ainda assim, valide a mesma regra no serviço que recebe o formulário. A validação do navegador melhora a experiência, mas uma requisição pode chegar por outros meios.
Mantenha rótulo e instrução visíveis
O ícone de calendário não explica o propósito do campo. Dê um rótulo visível e associe instruções quando houver regra que a interface não comunica sozinha.
<label for="inicio">Data de início</label><p id="inicio-ajuda">Escolha uma data entre 21 de setembro e 19 de dezembro.</p><input id="inicio" name="inicio" type="date" min="2026-09-21" max="2026-12-19" aria-describedby="inicio-ajuda"/>A WCAG sobre rótulos e instruções pede informação suficiente para a pessoa saber o que inserir. Não use placeholder como único rótulo. Ele some durante a digitação e pode não existir no controle nativo de todos os navegadores.
Se o campo aceita texto num formato específico, mostre o formato antes do erro. Use um exemplo realista e não dependa apenas de dd/mm/aaaa se o público pode não reconhecer a abreviação.
Não confunda limite visual com validação completa
min, max e step ajudam, mas não cobrem regras como:
- datas bloqueadas por unidade;
- feriados carregados por API;
- intervalo mínimo entre início e fim;
- disponibilidade alterada por outra reserva;
- prazo calculado no fuso da operação.
Quando a regra depende de dados atuais, trate o calendário como uma apresentação de disponibilidade, não como fonte final da verdade. O serviço precisa revalidar no envio e devolver uma mensagem ligada ao campo.
Não apague a escolha após um conflito. Preserve o valor, explique por que ele não serve e ofereça o próximo passo.
O guia sobre mensagens de erro e status acessíveis mostra como associar a falha ao campo e anunciar uma atualização sem interromper cada movimento.
Só construa um calendário próprio por necessidade real
Um calendário personalizado pode ser necessário quando a tarefa exige:
- mostrar disponibilidade por dia;
- escolher um intervalo;
- comparar datas com preços ou eventos;
- bloquear dias com uma regra que precisa ficar visível;
- oferecer uma experiência consistente comprovada nos ambientes suportados.
Personalização visual isolada não basta. Um calendário próprio precisa implementar diálogo, grade, foco, navegação, seleção, localização e retorno ao campo.
A W3C publica um exemplo de date picker em diálogo, mas avisa que exemplos da APG não são código pronto para produção e podem ter lacunas de suporte, principalmente em combinações móveis e de toque. Use o exemplo para estudar o contrato e teste a sua implementação.
Trate o popup como diálogo quando ele for modal
Se o calendário abre sobre a página e impede interação externa, ele precisa se comportar como diálogo modal:
- recebe um nome, normalmente o mês e o ano exibidos;
- move o foco para dentro ao abrir;
- mantém
TabeShift+Tabdentro enquanto estiver ativo; - fecha com
Esc; - oferece um botão visível para cancelar ou fechar;
- devolve o foco ao botão que o abriu;
- impede interação com o conteúdo externo de verdade.
O padrão de diálogo modal da W3C alerta que aria-modal="true" só deve ser usado quando o código também torna o restante da página inerte. Declarar modalidade sem implementar o comportamento pode esconder conteúdo de tecnologias assistivas enquanto ele continua clicável para outras pessoas.
O artigo sobre diálogos modais acessíveis detalha foco inicial, fechamento e restauração.
Use uma grade com navegação interna
Um calendário mensal não deve colocar cada dia na sequência de Tab. A página teria até 42 paradas antes dos botões seguintes.
Trate a grade como um único ponto na sequência da página. Dentro dela, use setas para mover entre dias:
Seta para esquerdaeSeta para direitamudam um dia;Seta para cimaeSeta para baixomudam uma semana;HomeeEndpodem ir ao início e ao fim da semana;Page UpePage Downpodem trocar o mês;EnterouEspaçoescolhe o dia em foco;Escfecha o diálogo sem confirmar.
O padrão de grid da W3C explica por que uma grade interativa exige gerenciamento de foco. Apenas uma célula entra na sequência de Tab, e o código move o foco dentro do componente.
Não capture setas quando o foco está num campo de texto destinado à digitação. O contexto define se a tecla edita o valor ou percorre a grade.
Diferencie hoje, foco e seleção
Um mesmo calendário pode ter:
- o dia de hoje;
- o dia com foco de teclado;
- a data selecionada;
- datas indisponíveis;
- datas fora do mês atual.
Esses estados não são sinônimos. Use estilos distintos e sem depender somente de cor. A pessoa precisa saber qual dia receberá Enter, qual valor será enviado e por que certas datas não podem ser escolhidas.
Quando o mês muda, anuncie o novo mês e ano de forma breve. Quando a seleção for confirmada e o diálogo fechar, o botão que reabre o calendário pode informar a data escolhida no nome ou numa descrição associada.
Evite anunciar cada deslocamento duas vezes. O foco na célula já fornece informação. Uma região viva deve comunicar mudanças que o foco sozinho não revela, como a troca de mês.
Escreva nomes completos para cada dia
Uma célula que mostra apenas 7 precisa de contexto. O nome acessível pode informar dia da semana, dia, mês e ano, além de indisponibilidade quando aplicável.
Exemplos:
segunda-feira, 7 de dezembro de 2026domingo, 13 de dezembro de 2026, indisponívelNão coloque frases longas em todas as células. Inclua apenas o contexto necessário para distinguir o valor e o estado.
Os cabeçalhos visuais abreviados da semana podem usar o atributo abbr para oferecer o nome completo a tecnologias assistivas. Mantenha o idioma do documento correto para que datas e nomes sejam pronunciados conforme o conteúdo. O guia sobre idioma da página cobre lang e mudanças de idioma.
Teste digitação, calendário e envio
O componente precisa aceitar o caminho que o produto promete. Se existe um campo editável e um botão de calendário, teste os dois.
| Cenário | Resultado esperado |
|---|---|
| digitação válida | valor reconhecido e enviado como a data correta |
| formato inválido | instrução ligada ao campo, sem apagar a entrada |
| limite mínimo | data anterior é bloqueada e explicada |
| mudança de mês | novo mês é visível e anunciado |
| navegação por setas | foco percorre dias sem mover a página |
Esc |
diálogo fecha sem alterar a escolha anterior |
| confirmação | valor muda e foco volta ao acionador |
| zoom e reflow | grade permanece operável sem esconder controles |
| toque | dias e botões têm área suficiente e separação |
| leitor de tela | rótulo, instrução, mês, dia e estado fazem sentido |
Inclua virada de mês, ano bissexto, datas no limite e troca de fuso no roteiro automatizado. Para a interação, faça teste manual. Um teste unitário pode confirmar o cálculo, mas não prova que o leitor de tela anuncia o componente nem que o foco retorna.
Use também os roteiros de zoom e reflow e alvos de toque.
Peça ao agente um resultado verificável
Evite um pedido aberto como “deixe o calendário acessível”. Forneça regras e ambientes:
Revise o campo Data da visita.
Regra:- amanhã até 90 dias;- domingos indisponíveis;- exibição no padrão brasileiro;- envio como yyyy-mm-dd, sem conversão para instante UTC.
Comece avaliando input type="date".Só mantenha o calendário personalizado se a disponibilidade visível exigir.Teste rótulo, instrução, erro, teclado, foco, zoom, toque e leitor de tela.Inclua virada de mês, ano bissexto e limites.Não publique antes de apresentar as evidências.O agente pode revisar código, executar testes e organizar resultados. Ele não deve inventar feriados, fuso, disponibilidade ou política de reserva.
Reteste depois da publicação
O build pode alterar scripts, estilos e ordem de carregamento. O domínio final também pode mudar idioma, cache ou chamadas de disponibilidade.
No Site no Ar, mantenha a saída pública em public/, execute deploy e aguarde deploy_status terminar, conforme o guia de Publicação. Depois abra a URL final e repita:
- digitação e seleção pelo calendário;
- teclado sem mouse;
- leitor de tela;
- largura pequena e zoom;
- data mínima, máxima e indisponível;
- resposta lenta ou falha da disponibilidade;
- valor recebido pelo destino do formulário.
Um seletor de data acessível começa com uma decisão simples. Use o controle nativo quando ele resolve a tarefa. Se o produto precisa de um calendário próprio, trate-o como um widget completo, com regras explícitas, foco previsível e validação repetida no destino.
