LLabanaat

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

PropTypeDefaultDescription
mode"single" | "range""single"Selection mode
selected / defaultSelectedDateControlled / uncontrolled selected date (mode="single")
onSelect(date: Date) => voidCalled when a date is selected (mode="single")
selectedRange / defaultSelectedRange{ from: Date; to?: Date }Controlled / uncontrolled selected range (mode="range")
onSelectRange(range) => voidCalled when the range changes (mode="range")
month / defaultMonthDateControlled / uncontrolled visible month
onMonthChange(date: Date) => voidCalled when the visible month changes
minDate / maxDateDateDisables dates outside this range
isDateDisabled(date: Date) => booleanDisables specific dates beyond the min/max range

Localization (non-English month/weekday labels) is a natural follow-up, not implemented here.