Tema
BaseDateRange
Período com data de início e data de fim, como a vigência de um contrato. As duas datas ficam lado a lado, sob um rótulo só, e cada uma tem o próprio rótulo curto ("Início" e "Fim"). O componente confere sozinho se o fim não vem antes do início.
Valor do v-model: {
"start": "2026-11-03",
"end": "2027-11-02"
} e {
"start": "",
"end": ""
}. Datas pela metade no prazo de execução: {
"start": false,
"end": false
}.
Uso
- Use para um período com começo e fim: vigência, prazo de execução, período de medição, afastamento. Para uma data só, use o
BaseDateInput. - O rótulo do grupo diz qual é o período ("Vigência"). Os rótulos das datas ficam curtos: "Início" e "Fim" por padrão. Troque com
start-labeleend-labelquando o nome da ponta ajudar ("Ordem de serviço", "Entrega da obra"). - O
v-modelé um objeto{ start, end }, cada data em ISOAAAA-MM-DDou''enquanto vazia ou incompleta. Formate paradd/mm/aaaasó na hora de mostrar. - Fim no mesmo dia do início vale. Fim antes do início mostra o erro: "O fim não pode ser antes do início. Confira as duas datas." Passe
invalid-textpara uma mensagem do seu caso. - O erro de ordem aparece quando o foco sai de uma das datas, nunca durante a digitação: enquanto o ano é digitado, o Chrome entrega
0002,0020e0202antes de2026, e o erro piscaria. Ele some assim que as datas ficam em ordem, mesmo no meio da digitação. - Valor posto pelo código (por exemplo, um contrato carregado do servidor) com o fim antes do início mostra o erro na hora, tanto ao trocar o objeto inteiro quanto ao mudar só
periodo.end. - Data pela metade (só dia e mês) ou impossível (31/02) chega ao
v-modelcomo'', igual a uma data vazia. Para separar as duas, usev-model:incomplete, um objeto{ start, end }que ficatruena ponta que sobrou pela metade. Assim a tela mostra "Data incompleta. Informe dia, mês e ano." cominvalideinvalid-text, ao sair do campo ou ao enviar, como noBaseDateInput. - Para limpar o período, ponha
{ start: '', end: '' }nov-modele{ start: false, end: false }noincomplete. Só assim somem as partes que o usuário deixou pela metade. - O calendário do fim só oferece dias a partir do início. Digitar uma data anterior continua possível, e aí vale o erro.
minemaxvalem para as duas datas. Diga o intervalo na ajuda: o navegador não explica por que um dia está bloqueado.- Para outras regras (período obrigatório, fora da vigência do contrato), valide ao sair do campo ou ao enviar e use
invalidcom uminvalid-textque diga como corrigir. Oinvalidmarca as duas datas; o erro de ordem marca só o fim. - Antes de enviar o formulário, confira a ordem com
isDateRangeOrdered(periodo), exportada pelo pacote. Ela devolvetruetambém quando falta uma das datas; trate o período obrigatório à parte. - Não coloque
BaseDateRangedentro deBaseField: o período já tem rótulo, ajuda e erro. Se acontecer, as datas mantêm os próprioside rótulos, mas o rótulo doBaseFieldfica sem campo.
Estados
- Inválido sempre mostra ícone e texto. Sem
invalid-text, aparece "Confira o início e o fim do período."; prefira uma mensagem que diga o que corrigir. - Aviso só aparece com
warn-text. Com erro e aviso ao mesmo tempo, vale o erro. - Somente leitura mostra o período sem permitir mudança; as datas seguem no foco do teclado e legíveis.
- Desabilitado é para quando o período não se aplica agora. Diga perto do campo por quê.
Tamanhos
Cada tamanho tem a altura do BaseInput correspondente, para o período alinhar com os outros campos da linha.
Estilo
As datas herdam o campo do BaseDateInput. Só o que é do período está abaixo.
| Propriedade | Token |
|---|---|
| Rótulo do grupo | --tj-text-secondary, --tj-text-sm, semibold; desabilitado --tj-text-placeholder, como no BaseFieldset |
| Rótulo de cada data | --tj-text-secondary, --tj-text-sm, regular; desabilitado --tj-text-placeholder |
| Colunas | duas iguais, espaço --tj-space-3 (o .tj-pair do protótipo v3); abaixo de 360 px, uma embaixo da outra |
| Rótulo até a data | --tj-space-1 |
| Borda com erro | --tj-support-error-text no fim (ordem) ou nas duas datas (invalid) |
| Borda com aviso | --tj-support-warning-text nas duas datas |
| Mensagem | ajuda --tj-text-helper; erro --tj-support-error-text; aviso --tj-support-warning-text; --tj-text-sm |
| Foco | anel --tj-ring em cada data |
Diferenças em relação ao protótipo v3: lá as datas só tinham aria-label ("Início da vigência"); aqui cada uma tem um rótulo visível, como no Carbon, para quem enxerga saber qual ponta é qual sem depender da ordem.
Código
vue
<script setup lang="ts">
import { ref } from 'vue'
import { BaseDateRange, isDateRangeOrdered, type DateRange } from '@lab-inovacao/design-system'
const vigencia = ref<DateRange>({ start: '', end: '' })
const vigenciaIncompleta = ref({ start: false, end: false })
</script>
<BaseDateRange v-model="vigencia" v-model:incomplete="vigenciaIncompleta" label="Vigência" helper-text="12 meses a partir da ordem de serviço." required />| Propriedade | Tipo | Padrão | Descrição |
|---|---|---|---|
v-model | { start: string, end: string } | { start: '', end: '' } | Datas em ISO AAAA-MM-DD; '' quando vazia ou incompleta |
v-model:incomplete | { start: boolean, end: boolean } | { start: false, end: false } | true na ponta com data pela metade ou impossível; false vindo do pai apaga o que sobrou |
label | string | — | Nome do período (obrigatório), vira a legenda |
startLabel / endLabel | string | 'Início' / 'Fim' | Rótulo visível de cada data |
min / max | string | — / '9999-12-31' | Primeira e última data aceitas nas duas pontas, em ISO; o fim também não oferece dias antes do início |
size | 'sm' | 'md' | 'lg' | 'md' | Altura das datas |
helperText | string | — | Ajuda abaixo das datas |
invalid | boolean | — | Marca as duas datas como inválidas, para regras da tela |
invalidText | string | ver Uso | Erro no lugar da ajuda, tanto com invalid quanto com o fim antes do início |
warn / warnText | boolean / string | — | Aviso no lugar da ajuda; sem warnText não aparece |
required / optional | boolean | — | Marca na legenda; required vai também para as duas datas |
disabled / readonly | boolean | — | Estados das duas datas |
hideLabel | boolean | — | Legenda só para leitor de tela |
Eventos:
update:modelValue: o objeto{ start, end }inteiro, a cada mudança de uma das datas.update:incomplete: o objeto{ start, end }inteiro, quando uma das datas passa a estar ou deixa de estar pela metade.
Também exportados: os tipos DateRange e DateRangeIncomplete e a função isDateRangeOrdered(periodo), a mesma regra que o componente usa.
Acessibilidade
Usa o papel group do WAI-ARIA, dado pelo <fieldset> nativo, como os grupos de campos do APG.
- O período é um
<fieldset>com<legend>: a legenda é o nome do grupo, que o leitor de tela anuncia ao entrar nele antes do rótulo da data ("Início", "Fim"). - Cada data é um
BaseDateInputcom<label for>visível. Cada parte (dia, mês, ano) é um campo giratório nativo e segue o teclado desse padrão: setas para cima e para baixo mudam a parte, seta para a direita e Tab passam para a seguinte, Backspace apaga. - Tab percorre dia, mês e ano do início, depois do fim, e sai do grupo; não há tecla própria do componente.
- Ajuda, erro e aviso ficam em
aria-describedbydas duas datas, para a mensagem ser lida quando qualquer uma recebe foco. - Com erro, a data marcada recebe
aria-invalid="true". A cor nunca é o único sinal: há sempre ícone e texto, inclusive seminvalid-text. requiredvai para as duas datas como atributo nativo. O asterisco fica escondido do leitor de tela.- O erro de ordem nunca aparece durante a digitação, então o leitor de tela não ouve uma mensagem que surge a cada tecla. Ele pode sumir no meio da digitação, assim que as datas ficam em ordem.
- Quando o foco sai de uma data e o erro de ordem aparece, uma região
aria-live="polite"escondida anuncia o texto do erro, porque é o componente, e não a tela, que decide a hora do erro. A região lê o texto que estiver visível nessa hora e esvazia quando as datas ficam em ordem. Uminvalidligado pela tela sozinho não é anunciado pelo componente: a tela decide a hora desse erro. - Dentro de um
BaseField(o que não se recomenda), as datas não herdam oiddo campo: cada rótulo continua apontando para a própria data. - O foco aparece com o anel
--tj-ringde 3 px em cada data. O componente não tem animação própria. - Testado com axe nestes estados: vazio, com ajuda, fim antes do início (com e sem
invalid-text, cominvalid, com aviso), erro de ordem depois de sair do campo, fim mudado pelo código no próprio objeto, data pela metade, inválido com e sem texto, aviso, obrigatório, opcional, somente leitura, desabilitado (também obrigatório), os três tamanhos, legenda oculta (também obrigatória) e rótulos trocados. O axe roda sem layout, então o contraste das cores é conferido na documentação renderizada.