useDateRangePicker

듀얼 월 캘린더, 호버 미리보기, 사전 설정 범위를 지원하는 날짜 범위 선택을 위한 Hook입니다.

Import

import { useDateRangePicker } from "react-date-range-picker-headless";

사용법

import { useState } from "react";
import { useDateRangePicker } from "react-date-range-picker-headless";
function MyDateRangePicker() {
const [range, setRange] = useState<{ start: Date | null; end: Date | null }>({
start: null,
end: null,
});
const picker = useDateRangePicker({
value: range,
onChange: setRange,
presets: [
{
label: "Last 7 days",
value: () => {
const end = new Date();
const start = new Date();
start.setDate(start.getDate() - 6);
return { start, end };
},
},
],
});
return (
<div ref={picker.containerRef}>
<button onClick={picker.handleToggle}>
{picker.displayValue || picker.locale.rangePlaceholder}
</button>
{picker.isOpen && (
<div ref={picker.popupRef} onKeyDown={picker.handleKeyDown}>
{/* 두 개의 캘린더를 나란히 표시 */}
{[picker.leftCalendar, picker.rightCalendar].map((cal, calIdx) => (
<div key={calIdx}>
<span>{picker.locale.formatMonthYear(cal.month)}</span>
{cal.weeks.flat().map((day, i) => {
if (!day) return <span key={i} />;
const dp = picker.getDayProps(day, cal.month);
return (
<button
key={i}
onClick={() => picker.handleDateClick(day)}
onMouseEnter={() => picker.handleDateHover(day)}
onMouseLeave={() => picker.handleDateHover(null)}
>
{dp.day}
</button>
);
})}
</div>
))}
{/* 사전 설정 */}
{picker.presets.map((preset, i) => (
<button
key={i}
onClick={() => picker.handlePresetClick(preset)}
style={{ fontWeight: i === picker.activePresetIndex ? "bold" : "normal" }}
>
{preset.label}
</button>
))}
<button onClick={picker.handleConfirm}>{picker.locale.confirm}</button>
</div>
)}
</div>
);
}

옵션

옵션타입기본값설명
value{ start: Date | null; end: Date | null }필수. 현재 범위 값입니다.
onChange(value: { start: Date | null; end: Date | null }) => void필수. 범위가 변경될 때 호출됩니다.
maxDaysnumber범위 내에서 허용되는 최대 일수 (포함).
minDaysnumber범위 내에서 필요한 최소 일수 (포함).
presetsDateRangePreset[]사전 정의된 날짜 범위 프리셋 (예: “지난 7일”, “이번 달”).
allowSingleDateInRangebooleantruefalse일 경우, 시작 날짜와 종료 날짜가 같은 범위 선택을 방지합니다.
minDateDate선택 가능한 가장 이른 날짜.
maxDateDate선택 가능한 가장 늦은 날짜.
localePartial<Locale>DEFAULT_LOCALE로케일 문자열을 재정의합니다.
initialMonthDate초기에 표시할 월.
sizeDatePickerSizeUI를 통해 전달됩니다.
weekStartsOnWeekDay"sunday"한 주의 시작 요일.
isDateUnavailable(date: Date) => boolean특정 날짜를 비활성화하는 사용자 정의 함수.
displayFormatstring표시 값에 대한 사용자 정의 형식 문자열.
openboolean제어되는 열림 상태.
initialOpenbooleanfalse초기 열림 상태 (비제어).
onOpenChange(open: boolean) => void열림 상태가 변경될 때의 콜백.
requiredbooleanfalsetrue일 때, handleClear는 아무 작업도 수행하지 않습니다.
todayDatenew Date()오늘 날짜를 재정의합니다.
onMonthChange(month: Date) => void표시된 월이 변경될 때의 콜백.
disablePastbooleanfalse오늘 이전의 모든 날짜를 비활성화합니다.
disableFuturebooleanfalse오늘 이후의 모든 날짜를 비활성화합니다.
showOutsideDaysbooleanfalse인접한 달의 날짜를 표시합니다.
highlightDatesDate[]강조할 날짜 배열.
shouldCloseOnSelectbooleanfalse종료 날짜가 선택되면 자동으로 확인합니다.
numberOfMonthsnumber2표시할 캘린더 월의 수.
captionLayoutCaptionLayout"buttons"캡션 레이아웃 모드.
fromYearnumbercurrent year - 100드롭다운의 시작 연도.
toYearnumbercurrent year + 10드롭다운의 종료 연도.

반환 값

이름타입설명
isOpenboolean팝업이 열려 있는지 여부.
tempStartDateDate | null임시 시작 날짜 (확인 전).
tempEndDateDate | null임시 종료 날짜 (확인 전).
hoveredDateDate | null현재 호버된 날짜 (범위 미리보기용).
leftMonthDate왼쪽 캘린더에 표시된 월.
rightMonthDate오른쪽 캘린더에 표시된 월.
localeLocale해결된 로케일 객체.
leftCalendarCalendarMonth왼쪽 패널의 캘린더 데이터.
rightCalendarCalendarMonth오른쪽 패널의 캘린더 데이터.
calendarsCalendarMonth[]모든 캘린더 월의 배열.
getDayProps(date: Date, referenceMonth?: Date) => DayProps캘린더의 날짜 셀에 대한 플래그를 계산합니다. 다중 월 레이아웃에서 월 외부의 날짜 감지가 올바르게 작동하도록 referenceMonth를 전달하세요.
displayValuestring확인된 범위의 포맷된 문자열.
hasValueboolean현재 범위가 확인되었는지 여부.
canConfirmboolean현재 선택이 확인에 유효한지 여부.
handleDateClick(date: Date) => void날짜 셀 클릭을 처리합니다. 첫 번째 클릭은 시작 날짜를, 두 번째 클릭은 종료 날짜를 설정합니다.
handleDateHover(date: Date | null) => void범위 미리보기를 위한 마우스 호버를 처리합니다.
handlePrevMonth() => void두 캘린더를 모두 한 달 뒤로 이동합니다.
handleNextMonth() => void두 캘린더를 모두 한 달 앞으로 이동합니다.
handleOpen() => void팝업을 엽니다.
handleClose() => void팝업을 닫습니다.
handleToggle() => void팝업을 토글합니다.
handleConfirm() => void선택을 확인하고 닫습니다.
handleCancel() => void취소하고 이전 값으로 되돌립니다.
handleClear() => void범위를 지웁니다 (required인 경우 아무 작업도 하지 않음).
handleGoToToday() => void오늘 날짜가 있는 월로 이동합니다.
containerRefRefObject<HTMLDivElement | null>바깥 영역 클릭 감지를 위해 래퍼에 연결합니다.
popupRefRefObject<HTMLDivElement | null>팝업 요소에 연결합니다.
focusedDateDate | null키보드로 포커스된 날짜.
handleKeyDown(e: KeyboardEvent<HTMLElement>) => void키보드 네비게이션 핸들러.
presetsDateRangePreset[]프리셋 배열 (렌더링을 위해 그대로 전달).
handlePresetClick(preset: DateRangePreset) => void프리셋 범위를 적용합니다.
activePresetIndexnumber현재 선택과 일치하는 프리셋의 인덱스 (없으면 -1).
yearsnumber[]드롭다운 모드를 위한 연도 배열.
monthsnumber[]드롭다운 모드를 위한 월 인덱스 배열.
handleYearSelect(year: number, calendarIndex?: number) => void표시된 연도를 설정합니다.
handleMonthSelect(month: number, calendarIndex?: number) => void표시된 월을 설정합니다.

주요 동작

범위 선택 흐름

  1. 첫 번째 클릭은 시작 날짜를 설정합니다 (종료 날짜는 지워짐)
  2. 두 번째 클릭은 종료 날짜를 설정합니다 (시작 날짜보다 이전이면 자동 교체)
  3. 세 번째 클릭은 범위를 재설정하고 새로운 범위를 시작합니다

호버 미리보기

사용자가 시작 날짜는 선택했지만 아직 종료 날짜를 선택하지 않은 동안, handleDateHoverhoveredDate를 업데이트합니다. getDayProps 함수는 이를 사용하여 isInHoverRangeisHoverTarget을 계산하여 잠재적인 범위의 미리보기를 표시할 수 있도록 합니다.

프리셋

프리셋은 정적 객체이거나 팩토리 함수일 수 있습니다:

const presets = [
{ label: "Today", value: { start: new Date(), end: new Date() } },
{
label: "Last 30 days",
value: () => {
const end = new Date();
const start = new Date();
start.setDate(start.getDate() - 29);
return { start, end };
},
},
];

activePresetIndex는 현재 선택과 일치하는 프리셋의 인덱스를 반환하며, 일치하는 것이 없으면 -1을 반환합니다.

maxDays / minDays

maxDays가 설정되면, 시작 날짜로부터 허용된 범위를 벗어나는 날짜는 자동으로 비활성화됩니다. minDays가 설정되면, 시작 날짜에 너무 가까운 날짜는 비활성화됩니다.

shouldCloseOnSelect

범위 선택기(range picker)의 경우, shouldCloseOnSelect시작 날짜가 아닌 종료 날짜가 선택되었을 때 자동 확인을 트리거합니다.