Pular para o conteúdo principal

DateRange

O DateRange é um componente para seleção de intervalos de datas, ideal para reservas, filtros de relatórios, períodos de trabalho e campanhas. Oferece uma interface intuitiva para seleção de data inicial e final.

Importação

import { DateRange } from '@useblu/ocean-react';

Importação específica (recomendado para tree-shaking)

import { DateRange } from '@useblu/ocean-react/DateRange';

Importação de tipos TypeScript

import type { DatePickerProps } from '@useblu/ocean-react';

// Uso em componente customizado
const MyDateRange: React.FC<DatePickerProps> = (props) => {
return <DateRange {...props} />;
};

Playground Interativo

Explore o componente DateRange no playground interativo do Storybook:

Documentação Completa

Para documentação técnica detalhada, exemplos de uso e API completa, consulte o Storybook do DateRange.

No Storybook você encontrará:

  • Controles interativos para testar todas as props
  • API gerada automaticamente com tipagem completa
  • Exemplos visuais de todas as variações e estados
  • Playground para experimentação rápida

Uso básico

import { useState } from 'react';

function BasicDateRange() {
const [dates, setDates] = useState({ from: '', to: '' });

return (
<DateRange
labels={{ from: 'Data inicial', to: 'Data final' }}
values={dates}
onSelect={setDates}
/>
);
}

Estados do Componente

Normal

import { useState } from 'react';

function NormalDateRange() {
const [dates, setDates] = useState({ from: '', to: '' });

return (
<DateRange
labels={{ from: 'Data inicial', to: 'Data final' }}
values={dates}
onSelect={setDates}
/>
);
}

Com erro

import { useState } from 'react';

function ErrorDateRange() {
const [dates, setDates] = useState({ from: '', to: '' });

return (
<DateRange
labels={{ from: 'Data inicial', to: 'Data final' }}
values={dates}
onSelect={setDates}
error={true}
helperText="Período obrigatório"
/>
);
}

Desabilitado

<DateRange
labels={{ from: 'Data inicial', to: 'Data final' }}
values={{ from: '', to: '' }}
onSelect={() => {}}
disabled={true}
/>

Estados Visuais

Veja todos os estados do DateRange:

Funcionalidades Especiais

Campos editáveis

import { useState } from 'react';

function EditableDateRange() {
const [dates, setDates] = useState({ from: '', to: '' });

return (
<DateRange
labels={{ from: 'Data inicial', to: 'Data final' }}
values={dates}
onSelect={setDates}
editable
helperText="Você pode digitar as datas ou usar o calendário"
/>
);
}

Limitando a partir de hoje

import { useState } from 'react';

function FutureDateRange() {
const [dates, setDates] = useState({ from: '', to: '' });

return (
<DateRange
labels={{ from: 'Check-in', to: 'Check-out' }}
values={dates}
onSelect={setDates}
startsToday
helperText="Selecione datas a partir de hoje"
/>
);
}

Restrições e Validações

Veja exemplos com diferentes restrições:

Bloqueando temporadas

Você pode combinar disabledDays com startsToday (ou qualquer outro critério) para impedir que o usuário selecione períodos inteiros. Use Matchers ou arrays de datas para bloquear intervalos específicos.

const blackout = [
{ from: new Date('2026-03-09'), to: new Date('2026-03-12') }, // março
{ from: new Date('2026-07-01'), to: new Date('2026-07-07') }, // julho
];

<DateRange
labels={{ from: 'Check-in', to: 'Check-out' }}
values={dates}
onSelect={setDates}
startsToday
disabledDays={blackout}
helperText="Evite temporadas de alta demanda"
/>;

Além da demonstração acima, use o storybook "Vacation Planning" para ver isso em ação:

Mensagem de tooltip para dias bloqueados

Quando um usuário tenta selecionar um dia bloqueado, você pode exibir uma mensagem explicativa através da prop disabledDaysMessage. O tooltip aparece automaticamente ao clicar em um dia desabilitado e desaparece após 5 segundos.

A prop aceita dois formatos:

  • string — mesma mensagem para todos os dias bloqueados
  • { date: Date; message: string }[] — mensagem específica por data; dias bloqueados sem entrada no array não exibem tooltip

Mensagem fixa para todos os dias bloqueados

import { useState } from 'react';

function DateRangeWithTooltip() {
const [dates, setDates] = useState({ from: '', to: '' });

return (
<DateRange
labels={{ from: 'Data inicial', to: 'Data final' }}
values={dates}
onSelect={setDates}
disabledDays={[
{ dayOfWeek: [0, 6] }, // Fins de semana
{ before: new Date() }, // Datas passadas
]}
disabledDaysMessage="Boletos pagos em finais de semana, feriados ou após às 16:00 são quitados no próximo dia útil."
helperText="Tente clicar em um dia bloqueado para ver o tooltip"
/>
);
}

Mensagem específica por data

Passe um array com entradas { date, message } para exibir uma mensagem diferente em cada data bloqueada. Dias bloqueados sem entrada no array não exibem tooltip.

import { useState } from 'react';

const addDays = (n) => {
const d = new Date();
d.setDate(d.getDate() + n);
return d;
};

const blockedDates = [
{ date: addDays(3), message: 'Manutenção programada neste dia' },
{ date: addDays(7), message: 'Feriado municipal' },
{ date: addDays(10), message: 'Bloqueio operacional' },
];

function DateRangeWithListMessages() {
const [dates, setDates] = useState({ from: '', to: '' });

return (
<DateRange
labels={{ from: 'Data inicial', to: 'Data final' }}
values={dates}
onSelect={setDates}
disabledDays={blockedDates.map((e) => e.date)}
disabledDaysMessage={blockedDates}
helperText="Clique nos dias marcados para ver o motivo"
/>
);
}

Internacionalização

O DateRange suporta diferentes idiomas através do date-fns:

Configuração de idiomas

import { ptBR, enUS } from 'date-fns/locale';

// Português (padrão)
<DateRange
labels={{ from: 'Data inicial', to: 'Data final' }}
values={dates}
onSelect={setDates}
locale={ptBR}
/>

// Inglês
<DateRange
labels={{ from: 'Start date', to: 'End date' }}
values={dates}
onSelect={setDates}
locale={enUS}
/>

Casos de Uso Práticos

Reservas e hospedagem

import { useState } from 'react';

function HotelReservation() {
const [stayPeriod, setStayPeriod] = useState({ from: '', to: '' });
const [carRental, setCarRental] = useState({ from: '', to: '' });

return (
<div>
<DateRange
labels={{ from: 'Check-in', to: 'Check-out' }}
values={stayPeriod}
onSelect={setStayPeriod}
startsToday
helperText="Período da sua estadia"
/>

<DateRange
labels={{ from: 'Início da reserva', to: 'Fim da reserva' }}
values={carRental}
onSelect={setCarRental}
helperText="Período de locação do veículo"
/>
</div>
);
}

Relatórios e análises

import { useState } from 'react';

function ReportFilters() {
const [reportPeriod, setReportPeriod] = useState({ from: '', to: '' });
const [analysisPeriod, setAnalysisPeriod] = useState({ from: '', to: '' });

return (
<div>
<DateRange
labels={{ from: 'Data inicial', to: 'Data final' }}
values={reportPeriod}
onSelect={setReportPeriod}
editable
helperText="Período para geração do relatório"
/>

<DateRange
labels={{ from: 'Início do período', to: 'Fim do período' }}
values={analysisPeriod}
onSelect={setAnalysisPeriod}
helperText="Intervalo de análise dos dados"
/>
</div>
);
}

Projetos e campanhas

import { useState } from 'react';

function ProjectPlanning() {
const [projectPeriod, setProjectPeriod] = useState({ from: '', to: '' });
const [campaignPeriod, setCampaignPeriod] = useState({ from: '', to: '' });

return (
<div>
<DateRange
labels={{ from: 'Início do projeto', to: 'Prazo de entrega' }}
values={projectPeriod}
onSelect={setProjectPeriod}
startsToday
/>

<DateRange
labels={{ from: 'Início da campanha', to: 'Fim da campanha' }}
values={campaignPeriod}
onSelect={setCampaignPeriod}
helperText="Período de veiculação"
/>
</div>
);
}

Validação

Implementação de validação

import { useState } from 'react';

function ValidatedDateRange() {
const [dates, setDates] = useState({ from: '', to: '' });
const [error, setError] = useState(false);

const handleSelect = (selectedDates: { from: string; to: string }) => {
setDates(selectedDates);
// Erro se ambas as datas não estão selecionadas
setError(!selectedDates.from || !selectedDates.to);
};

return (
<DateRange
labels={{ from: 'Data inicial', to: 'Data final' }}
values={dates}
onSelect={handleSelect}
error={error}
helperText={error ? 'Selecione ambas as datas' : 'Período válido'}
/>
);
}

API

Props

PropTipoPadrãoDescrição
labels{ from: string; to: string }-Labels dos campos inicial e final (obrigatório)
values{ from: string; to: string }-Valores das datas selecionadas (obrigatório)
onSelect(dates: { from: string; to: string }) => void-Função chamada ao selecionar datas (obrigatório)
editablebooleanfalsePermite edição manual dos campos
disabledbooleanfalseDesabilita o componente
errorbooleanfalseExibe estado de erro
helperTextstring-Texto de ajuda ou erro
startsTodaybooleanfalseLimita seleção a partir da data atual
disabledDaysMatcher | Matcher[] | ((date: Date) => boolean)-Bloqueia datas específicas no calendário
disabledDaysMessagestring | { date: Date; message: string }[]-Mensagem fixa ou lista de mensagens por data para dias bloqueados
localeLocaleptBRLocale do date-fns para internacionalização
classNamestring-Classes CSS adicionais

O disabledDays aceita matchers ({ from, to }, before, after, etc.) ou uma função para aplicar regras personalizadas. Combine-a com startsToday (ou use isoladamente) para bloquear temporadas ou feriados específicos.

disabledDaysMessage como array: dias bloqueados sem entrada correspondente no array não exibem tooltip. Use para comunicar motivos distintos por data (feriados, manutenções, bloqueios operacionais, etc.).

Eventos

  • onSelect: Disparado quando um intervalo de datas é selecionado no calendário

Acessibilidade

  • Navegação por teclado: Suporte completo para Tab, setas, Enter e Escape
  • Screen readers: Labels e estados anunciados corretamente
  • Foco visual: Indicação clara do elemento focado
  • ARIA attributes: Implementação correta de atributos ARIA
  • Contraste: Cores adequadas para diferentes níveis de visão
TeclaFunção
TabNavega entre elementos
Space / EnterAbre/fecha calendário
SetasNavega entre datas no calendário
Page Up/DownNavega entre meses
Home/EndVai para início/fim da semana
EscapeFecha o calendário

Melhores Práticas

✅ Faça

  • Use DateRange para seleção de intervalos de datas
  • Configure startsToday para períodos futuros obrigatórios
  • Forneça labels descritivos para cada campo
  • Use helperText para explicar o propósito do intervalo
  • Implemente validação para garantir que ambas as datas são selecionadas
  • Use locale apropriado para seu público-alvo

❌ Não faça

  • Não use DateRange para datas únicas (use DatePicker)
  • Não omita onSelect, values ou labels (props obrigatórias)
  • Não ignore validação de intervalos inválidos
  • Não use labels genéricos sem contexto
  • Não desabilite sem explicar o motivo no helperText

Quando Usar

✅ Ideal para:

  • Reservas e estadias (hotéis, viagens)
  • Períodos de trabalho e projetos
  • Filtros de relatórios por data
  • Promoções e campanhas com duração
  • Períodos de férias e ausências
  • Análises temporais de dados

❌ Evite para:

  • Seleção de datas únicas (use DatePicker)
  • Seleção de horários (use TimePicker dedicado)
  • Múltiplas datas não contínuas
  • Intervalos muito específicos com granularidade de horas

CSS Classes

O componente gera as seguintes classes CSS:

ClasseDescrição
.ods-dateClasse base aplicada ao componente
.ods-date__calendarContainer do calendário modal
.ods-date__captionTítulo do mês no DateRange
.ods-date__navButtonsContainer dos botões de navegação
.ods-date__navButtonPrevBotão de mês anterior
.ods-date__navButtonNextBotão de próximo mês
.ods-date__navIconÍcone dos botões de navegação
.ods-date__tableTabela do calendário
.ods-date__headCabeçalho da tabela (dias da semana)
.ods-date__bodyCorpo da tabela (dias do mês)
.ods-date__rowLinha da tabela
.ods-date__cellCélula da tabela
.ods-date__dayElemento do dia
.ods-date__todayDia atual destacado
.ods-date__selectedDias selecionados
.ods-date__disabledDias desabilitados
.ods-date__selectedStartPrimeiro dia do range selecionado
.ods-date__selectedEndÚltimo dia do range selecionado
.ods-date__selectedMiddleDias intermediários do range selecionado