DatePicker
input, trigger, popover, 캘린더 그리드로 이뤄진 단일 날짜 선택.
import { DatePicker } from '@kalyx/react';
기본 사용
import { useState } from 'react';
import { DatePicker, type ISODateString } from '@kalyx/react';
function Example() {
const [date, setDate] = useState<ISODateString | null>(null);
return (
<DatePicker value={date} onChange={setDate}>
<DatePicker.Input placeholder="YYYY-MM-DD" />
<DatePicker.Trigger />
<DatePicker.Popover>
<DatePicker.Calendar />
</DatePicker.Popover>
</DatePicker>
);
}
직접 사용해보기
<DatePicker> (Root)
상태를 보관하고 서브 컴포넌트에 컨텍스트를 제공합니다. value 제공 시 제어형, defaultValue만 제공 시 비제어형.
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
value | ISODateString | null | — | 제어형 선택 날짜. |
defaultValue | ISODateString | — | 비제어형 초기값. value 있으면 무시. |
onChange | (value: ISODateString | null) => void | — | 선택 또는 초기화 시 호출. |
disabled | DisabledRule[] | boolean | false | 특정 날짜 비활성화 또는 전체 비활성. |
readOnly | boolean | false | 변경 방지, 표시용으로 선택 가능. |
weekStartsOn | 0 | 1 | 0 | 0 = 일요일, 1 = 월요일. |
displayFormat | string | 'yyyy-MM-dd' | date-fns 포맷 문자열. |
locale | string | 'en-US' | BCP 47 로케일 태그. |
adapter | DateAdapter | DateFnsAdapter | 커스텀 날짜 어댑터. |
children | ReactNode | — | 서브 컴포넌트. |
DisabledRule
type DisabledRule =
| { date: ISODateString } // 특정 일자
| { before: ISODateString } // 그 이전 모든 날짜
| { after: ISODateString } // 그 이후 모든 날짜
| { dayOfWeek: number[] }; // 0 = 일 … 6 = 토
주말과 오늘 이전 모든 날짜 비활성화:
<DatePicker
value={iso}
onChange={setIso}
disabled={[{ dayOfWeek: [0, 6] }, { before: new Date().toISOString() }]}
/>
<DatePicker.Input>
<input role="combobox">를 렌더합니다. blur/Enter에서 타이핑된 날짜를 파싱합니다. value, onChange, type을 제외한 모든 표준 input 속성을 확장합니다.
| Prop | 타입 | 설명 |
|---|---|---|
format | string | Root의 displayFormat 오버라이드. |
내부 <input>으로 ref가 전달됩니다.
<DatePicker.Trigger>
popover를 토글하는 버튼. children이 없으면 기본 캘린더 아이콘을 렌더합니다. type을 제외한 모든 표준 버튼 속성을 확장합니다.
| Prop | 타입 | 설명 |
|---|---|---|
children | ReactNode | 기본 아이콘 오버라이드. |
<DatePicker.Trigger aria-label="캘린더 열기">
📅
</DatePicker.Trigger>
<DatePicker.Popover>
Floating UI 위치 계산 포털 (role="dialog", aria-modal="false"). 바깥 클릭 해제, Escape 닫기, 포커스 복원을 처리합니다.
role을 제외한 표준 <div> 속성 확장.
<DatePicker.Popover className="rounded-lg border bg-white p-3 shadow-lg">
<DatePicker.Calendar />
</DatePicker.Popover>
<DatePicker.Calendar>
월 그리드. 완전한 키보드 네비게이션 (접근성 참조).
| Prop | 타입 | 설명 |
|---|---|---|
classNames | DatePickerCalendarClassNames | 내부 슬롯 스타일. |
onTitleClick | () => void | 월/연 타이틀 클릭 시 — MonthGrid/YearGrid와 연결. |
classNames 키
type DatePickerCalendarClassNames = {
root?: string;
header?: string; // 타이틀 + nav 버튼 감싸기
title?: string; // "2026년 4월"
navButton?: string; // 이전 / 다음 버튼
grid?: string; // <table role="grid">
gridRow?: string; // <tr>
gridCell?: string; // <td role="gridcell">
day?: string; // 날짜 버튼
daySelected?: string; // day.isSelected일 때
dayToday?: string; // day.isToday일 때
dayDisabled?: string; // day.isDisabled일 때
dayOutsideMonth?: string;// 6주 뷰 패딩
weekdayHeader?: string; // "월", "화", …
};
<DatePicker.MonthGrid> (선택)
3×4 월 그리드. 월 바로 이동이 필요할 때 mount.
| Prop | 타입 | 설명 |
|---|---|---|
classNames | DatePickerMonthGridClassNames | 스타일. |
onSelect | () => void | 월 선택 후 호출 — 보통 Calendar로 복귀. |
onTitleClick | () => void | 연도 타이틀 클릭 — YearGrid와 연결. |
type DatePickerMonthGridClassNames = {
root?: string;
header?: string;
title?: string;
navButton?: string;
grid?: string;
month?: string;
monthSelected?: string;
monthCurrent?: string;
};
<DatePicker.YearGrid> (선택)
페이지네이션되는 연도 그리드 (12년 단위).
| Prop | 타입 | 설명 |
|---|---|---|
classNames | DatePickerYearGridClassNames | 스타일. |
onSelect | () => void | 연도 선택 후 호출. |
type DatePickerYearGridClassNames = {
root?: string;
header?: string;
title?: string;
navButton?: string;
grid?: string;
year?: string;
yearSelected?: string;
yearCurrent?: string;
};
패턴
월 / 연도 네비게이션
import { useState } from 'react';
import { DatePicker } from '@kalyx/react';
function WithJump() {
const [view, setView] = useState<'days' | 'months' | 'years'>('days');
return (
<DatePicker value={iso} onChange={setIso}>
<DatePicker.Input />
<DatePicker.Popover>
{view === 'days' && (
<DatePicker.Calendar onTitleClick={() => setView('months')} />
)}
{view === 'months' && (
<DatePicker.MonthGrid
onSelect={() => setView('days')}
onTitleClick={() => setView('years')}
/>
)}
{view === 'years' && (
<DatePicker.YearGrid onSelect={() => setView('months')} />
)}
</DatePicker.Popover>
</DatePicker>
);
}
비제어 + 폼 제출
<form action="/api/save" method="post">
<DatePicker name="startDate" defaultValue="2026-04-15T00:00:00.000Z">
<DatePicker.Input name="startDate" />
<DatePicker.Popover>
<DatePicker.Calendar />
</DatePicker.Popover>
</DatePicker>
<button type="submit">저장</button>
</form>
최소 / 최대 날짜
별도의 minDate/maxDate prop은 없습니다 — 동일한 규칙을 disabled로 표현하세요.
<DatePicker
disabled={[
{ before: '2026-01-01T00:00:00.000Z' },
{ after: '2026-12-31T00:00:00.000Z' },
]}
value={iso}
onChange={setIso}
/>