Calendar
A month-view date grid, implemented directly against the WAI-ARIA grid pattern — roving tabindex, arrow-key navigation between days, Home/End for week bounds, PageUp/PageDown for month navigation — since no Radix primitive exists for this. A foundation for a future, richer DatePicker variant; the current DatePicker uses the native input by design and doesn't depend on this component.
function Demo() { const [selected, setSelected] = useState(); return <Calendar selected={selected} onSelect={setSelected} defaultMonth={new Date(2026, 0, 1)} />; } render(<Demo />);
Editable — change the code above and the preview updates live.
Click a date, or focus the grid (Tab into it) and use the arrow keys, Home/End, and Page Up/Page Down.
Range selection
Pass mode="range" for start/end date selection — first click sets the start, second click sets the end (automatically swapped if it lands before the start), and a third click begins a new range.
function Demo() { const [range, setRange] = useState(); return ( <Calendar mode="range" selectedRange={range} onSelectRange={setRange} defaultMonth={new Date(2026, 0, 1)} /> ); } render(<Demo />);
Editable — change the code above and the preview updates live.
Min/max date range
A separate concept from range selection above — this disables individual dates outside a fixed window, while still selecting a single date.
<Calendar defaultMonth={new Date(2026, 0, 1)} minDate={new Date(2026, 0, 10)} maxDate={new Date(2026, 0, 25)} />
Editable — change the code above and the preview updates live.
Installation
import { Calendar } from "@labanaat/ui/calendar";Props
| Prop | Type | Default | Description |
|---|---|---|---|
| mode | "single" | "range" | "single" | Selection mode |
| selected / defaultSelected | Date | — | Controlled / uncontrolled selected date (mode="single") |
| onSelect | (date: Date) => void | — | Called when a date is selected (mode="single") |
| selectedRange / defaultSelectedRange | { from: Date; to?: Date } | — | Controlled / uncontrolled selected range (mode="range") |
| onSelectRange | (range) => void | — | Called when the range changes (mode="range") |
| month / defaultMonth | Date | — | Controlled / uncontrolled visible month |
| onMonthChange | (date: Date) => void | — | Called when the visible month changes |
| minDate / maxDate | Date | — | Disables dates outside this range |
| isDateDisabled | (date: Date) => boolean | — | Disables specific dates beyond the min/max range |
Localization (non-English month/weekday labels) is a natural follow-up, not implemented here.