Pular para o conteúdo
// visualizar em
salvo em todas as páginas

Range calendar

Calendário de intervalo que mostra um mês e deixa a pessoa escolher um dia de início e um de fim em dois cliques. Use para hospedagens, viagens, férias e períodos de relatório.

Feito com React AriaPadrão WAI-ARIA GridComponente clienteCódigo ↗
minimal · light · #3fa34d

Datas da viagem, outubro de 2026

27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
weekdayStyle
firstDayOfWeek
allowsNonContiguousRanges
readOnly
disabled

Instalação

Configure o Camaleo uma vez (Instalação) e importe o que precisar. As datas são objetos do @internationalized/date, reexportados pelo Camaleo.

import { RangeCalendar, CalendarDate, isWeekend } from "@camaleo/react";

Anatomia

As mesmas partes do Calendar. Os dias entre o início e o fim ganham o fundo do intervalo.

título‹ ›início · intervalo · fimrodapé
[data-slot="range-calendar"][data-slot="calendar-title"] · [data-slot="calendar-nav-button"] · [data-slot="calendar-footer"][data-slot="calendar-grid"] · [data-slot="calendar-cell"]

Exemplos

Cada exemplo é um arquivo real que você pode copiar. Todos usam o estilo, o modo e a cor escolhidos na barra acima.

minimal · light · #3fa34d

Datas da viagem, outubro de 2026

27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

Datas da hospedagem, outubro de 2026

27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
18 de out. – 23 de out.5 noites

Controlado, com contagem de noites

Clique na entrada e depois na saída. end.compare(start) dá o número de noites, e o rodapé repete o período em palavras.

Temporada de verão, dezembro de 2026

29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
Reservas de 01/12 a 28/02.

Mínimo e máximo

minValue e maxValue mantêm o intervalo dentro da temporada, e as setas param no primeiro e no último mês.

Estadia mínima, outubro de 2026

27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
A estadia precisa ter pelo menos 2 noites.

Estadia mínima

Escolha uma noite só. Confira a duração no onChange, use invalid e diga a regra no rodapé, que é um status ao vivo.

Datas do chalé, outubro de 2026

27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
De 20 a 22/10 está reservado. A estadia não pode passar por esses dias.

Noites reservadas

Tente passar pelo dia 20/10. Por padrão, um intervalo não atravessa dias indisponíveis, então ninguém reserva por cima de outro hóspede.

Férias, outubro de 2026

27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Fins de semana não contam.10 dias úteis

Atravessando fins de semana

allowsNonContiguousRanges deixa o intervalo passar por dias indisponíveis. Conte só os dias que importam, como os dias úteis de folga.

Sprint 21, outubro de 2026

28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
Duas semanas, de segunda a domingo.

Semana começando na segunda

firstDayOfWeek="mon" faz uma sprint de duas semanas ocupar duas linhas inteiras.

Sua reserva, outubro de 2026

27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Confirmada. Alterações só por telefone.

Somente leitura

readOnly mostra uma hospedagem confirmada. A pessoa ainda percorre os dias pelo teclado e ouve as datas.

Em contexto

Intervalos movem reservas, pedidos e relatórios. São pedaços inteiros de interface para copiar, no estilo que você escolheu.

Pousada Maré Alta · Paraty

Quarto com vista para o mar, café da manhã incluso. R$ 420 por noite.

Datas da hospedagem, outubro de 2026

27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
3 noites

Total R$ 1.260

Hospedagem com preçoCard · RangeCalendar · Button
18 dias disponíveis

Pedir férias

Sua gestora, Patrícia Lima, recebe o pedido.

Férias, novembro de 2026

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1
2
3
4
5
Fins de semana não contam.10 dias úteis
Pedido de fériasCard · Badge · RangeCalendar · Button

Relatório de vendas

Dados até 28/10/2026.

Período do relatório, outubro de 2026

27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Período de relatório com atalhosCard · ButtonGroup · RangeCalendar · Button

Boas práticas

Datas da hospedagem, outubro de 2026

27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
18 a 23/10 · 5 noites
FaçaResuma o intervalo em palavras.

"5 noites" confirma a escolha num relance e é lido pelo leitor de tela.

Datas da hospedagem, outubro de 2026

27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
EviteSó o destaque.

A pessoa conta as células para saber quanto escolheu, e erra por um.

Datas do chalé, outubro de 2026

27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
De 20 a 22/10 está reservado. A estadia não pode passar por esses dias.
FaçaMarque os dias reservados antes da escolha.

isDateUnavailable para o intervalo nas noites reservadas, e o rodapé diz o motivo.

Datas do chalé, outubro de 2026

27
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
De 20 a 22/10 já está reservado. Escolha outras datas.
EviteRecusar o intervalo depois de escolhido.

Todos os dias pareciam livres, então o erro pega de surpresa e a pessoa recomeça.

Props

PropriedadeTipoPadrãoDescrição
classNamestring—Classes do elemento raiz.
styleCSSProperties—Estilos inline do elemento raiz.
disabledboolean—Desativa todos os dias e as setas, e tira a grade da ordem do Tab.
readOnlybooleanfalseMostra o intervalo sem deixar a pessoa mudar. Os dias continuam focáveis.
invalidboolean—Marca o intervalo como inválido, para regras que a sua aplicação confere, como uma estadia mínima.
localestring—Idioma BCP 47 dos nomes dos meses, dos dias da semana e do primeiro dia da semana, como "pt-BR". Por padrão, o do I18nProvider mais próximo ou o do navegador.
weekdayStyleWeekdayStyle"short"Como os dias da semana aparecem no cabeçalho: "narrow", "short" (padrão) ou "long".
previousLabelstring—Nome acessível da seta do mês anterior. Por padrão, o "Anterior" traduzido do React Aria.
nextLabelstring—Nome acessível da seta do próximo mês. Por padrão, o "Próximo" traduzido do React Aria.
footerReactNode—Conteúdo abaixo da grade: o período em palavras, as noites ou um total.
value{ start: DateValue; end: DateValue } | null—O intervalo escolhido, com start e end (controlado).
defaultValue{ start: DateValue; end: DateValue } | null—O intervalo escolhido no início (não controlado).
onChange(value: { start; end }) => void—Chamada quando a pessoa termina de escolher o intervalo.
minValueDateValue | null—A primeira data que pode ser escolhida.
maxValueDateValue | null—A última data que pode ser escolhida.
autoFocusbooleanfalseFoca o calendário ao montar.
focusedValueDateValue | null—O dia focado (controlado). Define também o mês visível.
defaultFocusedValueDateValue | null—O dia focado quando o calendário aparece (não controlado). Define o mês inicial.
onFocusChange(date: CalendarDate) => void—Chamada quando o dia focado muda, inclusive ao trocar de mês.
firstDayOfWeek"sun" | "mon" | "tue" | "wed" | "thu" | "fri" | "sat"—O dia que começa a semana. Por padrão, o do idioma.
allowsNonContiguousRangesboolean—Deixa o intervalo atravessar dias indisponíveis, como fins de semana numa folga.
isDateUnavailable(date: DateValue) => boolean—Devolve true para os dias que não podem ser escolhidos, como noites já reservadas.

O tipo do valor é exportado como DateRange. As outras props de range calendar do React Aria passam direto, como pageBehavior e createCalendar.

Styling hooks

Mude o visual sem copiar o componente: use os atributos ou defina os tokens num elemento pai, num estilo ou no próprio calendário.

Atributos

data-slot"range-calendar" · "calendar-header" · "calendar-grid" · "calendar-cell" · "calendar-footer"
data-selectedpresente em todos os dias do intervalo
data-selection-start · data-selection-endpresente no primeiro · no último dia do intervalo
data-todaypresente na data de hoje
data-unavailablepresente nos dias que o isDateUnavailable recusa
data-disabled · data-outside-monthpresente nos dias fora do mínimo/máximo · nos dias de outro mês

Tokens que ele lê

Cor

--cml-accent--cml-accent-fg--cml-accent-text--cml-border--cml-border-control--cml-button-outline-bg--cml-button-outline-border--cml-button-outline-shadow--cml-button-solid-shadow--cml-card-border--cml-card-shadow--cml-fg--cml-fg-muted--cml-fg-secondary--cml-focus-offset--cml-focus-ring--cml-focus-width--cml-radius-surface--cml-surface-raised

Forma e tamanho

--cml-border-width--cml-font-size-help--cml-radius-control-sm

Tipografia e movimento

--cml-duration-fast--cml-ease-standard--cml-font-control--cml-font-display--cml-font-label--cml-font-weight-display

Só deste componente

--cml-button-solid-image--cml-calendar-bg--cml-calendar-cell-font--cml-calendar-cell-radius--cml-calendar-cell-size--cml-calendar-cell-size-font--cml-calendar-cell-weight--cml-calendar-header-fg--cml-calendar-header-size--cml-calendar-header-tracking--cml-calendar-header-transform--cml-calendar-header-weight--cml-calendar-nav-radius--cml-calendar-nav-size--cml-calendar-padding--cml-calendar-radius--cml-calendar-range-border--cml-calendar-range-fg--cml-calendar-selected-bg--cml-calendar-selected-border--cml-calendar-selected-fg--cml-calendar-title-font--cml-calendar-title-size--cml-calendar-title-tracking--cml-calendar-title-transform--cml-calendar-title-weight--cml-calendar-today-bg--cml-calendar-today-border--cml-calendar-today-fg--cml-calendar-width--cml-corner-shape--cml-disabled-opacity--cml-item-highlight
/* uma faixa mais suave entre as duas pontas */
.booking [data-slot="range-calendar"] {
  --cml-calendar-range-bg: color-mix(in oklab, var(--cml-accent) 8%, transparent);
}

Acessibilidade

SetasMovem o foco um dia, ou uma semana para cima e para baixo. Depois do primeiro clique, o intervalo acompanha o foco.
Enter / EspaçoEscolhe o início e depois o fim do intervalo.
EscapeCancela um intervalo que tem início mas ainda não tem fim.
Home / EndLevam o foco ao primeiro ou ao último dia do mês.
Page Up / Page DownVão para o mês anterior ou o próximo. Com Shift, um ano.

Relacionados

Esta página foi útil? · Editar esta página no GitHub