Installation
Usage
"use client"
import { useState } from "react"
import { DatePicker, type DateRange } from "@/components/date-picker"
export function Booking() {
const [stay, setStay] = useState<DateRange>({ from: null, to: null })
return (
<div className="flex gap-4">
<DatePicker label="Delivery date" name="delivery" disableWeekends />
<DatePicker label="Your stay" mode="range" months={2} value={stay} onValueChange={setStay} />
</div>
)
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| label | string | — | Visible label and accessible name. |
| mode | "single" | "range" | "single" | One date, or a first and last day. |
| value / defaultValue | string | null · { from, to } | — / null | ISO dates, e.g. "2026-10-10". |
| onValueChange | (value) => void | — | Called with the new date or range. |
| min / max | string | — | Earliest and latest choosable dates. |
| disableWeekends | boolean | false | Rule out Saturdays and Sundays. |
| isDateDisabled | (date: string) => boolean | — | Rule out any other dates. |
| months | 1 | 2 | 1 | Months side by side (two on wide screens). |
| inline | boolean | false | Show the calendar on the page instead of in a popover. |
| weekStartsOn | 0 | 1 | 1 | Sunday or Monday first. |
| locale | string | visitor's | Month and day names. |
| placeholder | string | "Pick a date" | Trigger text before a choice. |
| name | string | — | Form field; a range submits "2026-10-10/2026-10-17". |
| presets | { label, value }[] | — | Quick choices beside the calendar; value is a date, a range, or a function of today. |
| hideLabel / disabled | boolean | false | Visually hidden label; disabled trigger. |
| --date-accent / --date-accent-foreground | CSS variable | --primary / --primary-foreground | Selected day colours. |
Accessibility
- WAI-ARIA date picker: the calendar is a grid; arrows move by day and week, Home/End to the week's ends, PageUp/PageDown by month (Shift: by year).
- Each day is announced in full, with "today" and "unavailable" where they apply; the month heading is a polite live region.
- Opening focuses the chosen day or today; Escape closes and returns focus to the trigger.
- Unavailable days stay focusable (so the grid can be explored) but can't be chosen; they're also struck through, not only dimmed.
- Month changes slide; instantly under prefers-reduced-motion.
- Presets are a labelled group of buttons, the active one marked with aria-pressed.
Changelog
- v1.0.0Latest
First release.