composed · Composed pattern
DatePicker
@devalok/shilp-sutra/composed/date-pickerView in Storybook Hand-curated previews ship in rolling waves. See it live in Storybook →
Reference
Props
DatePicker
value?: Date | null
onChange?: (date: Date | null) => void
placeholder: string (default: "Pick a date")
formatStr: string (default: "MMM d, yyyy")
minDate: Date
maxDate: Date
disabledDates: (date: Date) => boolean
className: string
DateRangePicker
startDate?: Date | null
endDate?: Date | null
onChange?: (range: { start: Date | null, end: Date | null }) => void
placeholder: string (default: "Pick a date range")
formatStr: string (default: "MMM d, yyyy")
minDate: Date
maxDate: Date
disabledDates: (date: Date) => boolean
presets: PresetKey[] (shows quick-select sidebar)
numberOfMonths: number (default: 1)
DateTimePicker
value: Date | null
onChange: (date: Date | null) => void
minDate: Date
maxDate: Date
disabledDates: (date: Date) => boolean
timeFormat: "12h" | "24h"
minuteStep: number
placeholder: string
className: string
TimePicker
value?: Date | null (time stored as a Date object)
onChange?: (date: Date) => void
format: "12h" | "24h" (default: "12h")
minuteStep: number (default: 1)
secondStep: number (default: 1)
showSeconds: boolean (default: false)
placeholder: string (default: "Pick a time")
disabled: boolean (default: false)
className: string
CalendarGrid
currentMonth: Date (REQUIRED)
selected?: Date | null
rangeStart?: Date | null
rangeEnd?: Date | null
hoverDate?: Date | null
onSelect: (date: Date) => void (REQUIRED)
onHover?: (date: Date | null) => void
onMonthChange: (date: Date) => void (REQUIRED)
onHeaderClick?: () => void
disabledDates: (date: Date) => boolean
minDate: Date
maxDate: Date
hidePrevNav: boolean
hideNextNav: boolean
events: CalendarEvent[] — { date: Date, color?: string, label?: string }
YearPicker
currentYear: number (REQUIRED)
selectedYear: number
onYearSelect: (year: number) => void (REQUIRED)
minDate: Date
maxDate: Date
MonthPicker
currentYear: number (REQUIRED)
selectedMonth: number (0-11)
onMonthSelect: (month: number) => void (REQUIRED)
minDate: Date
maxDate: Date
Presets
presets: PresetKey[] (REQUIRED)
onSelect: (start: Date, end: Date) => void (REQUIRED)
className: string
PresetKey: 'today' | 'yesterday' | 'last7days' | 'last30days' | 'thisMonth' | 'lastMonth' | 'thisYear'
useCalendar hook
useCalendar(initialMonth?: Date) => { currentMonth, setCurrentMonth, goToPreviousMonth, goToNextMonth, goToMonth, goToYear }
Defaults
DatePicker: placeholder="Pick a date", formatStr="MMM d, yyyy"
DateRangePicker: placeholder="Pick a date range", formatStr="MMM d, yyyy", numberOfMonths=1
TimePicker: format="12h", minuteStep=1, secondStep=1, showSeconds=false
Example
<DatePicker value={date} onChange={setDate} placeholder="Select date" />
<DateRangePicker
startDate={start}
endDate={end}
onChange={({ start, end }) => { setStart(start); setEnd(end); }}
/>
<DateTimePicker value={dateTime} onChange={setDateTime} timeFormat="12h" minuteStep={15} />
<TimePicker value={time} onChange={setTime} format="24h" minuteStep={15} />
Composability
- 7 sub-components in one kit: DatePicker, DateRangePicker, DateTimePicker, TimePicker, CalendarGrid, MonthPicker, YearPicker, Presets. Built on Popover (trigger + calendar content) + date-fns.
- Layered abstractions:
- High-level: DatePicker / DateRangePicker / DateTimePicker / TimePicker (use these 95% of the time — Popover-wrapped, single-field pickers with formatted value display).
- Low-level: CalendarGrid / MonthPicker / YearPicker (use for custom picker layouts, inline calendars, dashboards with embedded date selection).
- useCalendar hook manages month navigation state — use it when building custom picker UI (e.g. inline calendar with custom header).
- Presets component is standalone — drop it next to a DateRangePicker's calendar for quick-select sidebars (Today / Last 7 days / This month / etc.).
- Events on calendar: CalendarGrid accepts
events: { date, color, label }[]— renders up to 3 colored dots per day cell. Useful for availability / booked-days highlights. - min/max/disabledDates are shared contract across the whole family — pass the same bounds config to any date picker variant.
Gotchas
- TimePicker stores time inside a Date object — only hours/minutes/seconds are meaningful
- CalendarGrid is a low-level building block — prefer DatePicker/DateRangePicker for most use cases
- MonthPicker month values are 0-indexed (Jan=0, Dec=11) — same as JavaScript
Date.getMonth() - YearPicker displays a 12-year grid based on the decade of
currentYear - CalendarGrid supports up to 3 event dots per day cell
- useCalendar is a convenience hook for managing calendar month state
Changes
v0.18.0
- Fixed Added
aria-labelto DatePicker/DateRangePicker trigger buttons
v0.4.2
- Changed DateRangePicker default
formatStrfrom'MMM d'to'MMM d, yyyy'
v0.1.0
- Added Initial release