Date Picker
A date field that opens a calendar under it. Its trigger is Select's, so the two line up in a form: the same four sizes, label, helper text and focus ring. It holds one day or a range, and shows it as Jan 20, 2026, or 20 يناير 2026 on an Arabic page.
Installation
npx @smicolon/fasla-ui@latest add date-pickerRun init once per project before adding components. See Installation.
Preview
Sizes
Four sizes: xs is 28px tall, sm 32px, md 36px and lg 40px, the same as Select. Only the height and the gap between the icon and the text change: the padding is 12px and the calendar icon 16px at every size.
States
Focus is a real state, not a prop: tab to the field, or open it. The trigger draws the focus ring on keyboard focus and for as long as the calendar is open. disabled dims the whole field to half opacity, its label and helper text included.
Range
mode="range" holds a start and an end, joined with a dash. The calendar stays open after the first press and closes once both ends are chosen. Set numberOfMonths to 2 to open two months.
Beside a Select
The label, the note at the end of the label row and the helper text work as on Select, and the trigger is Select's own, so a Date Picker and a Select line up side by side at every size.
Optional
Where we deliver your order.
The calendar
The calendar opens 4px under the trigger, lined up with its start edge, and flips above it when there is no room below. Focus moves to the chosen day, or today, so the arrow keys work at once. Choosing a day closes it; Escape closes it too, and returns focus to the trigger.
In a form
Give the field a name and it submits with its form: a day as 2026-01-20, and a range as 2026-01-20/2026-02-09. Pass Calendar props through calendarProps, such as month and year menus for a date of birth.
Accessibility
- The trigger is a
buttonthat opens adialog. It is named by its label and its value together, so a screen reader says both, and its helper text is read with it. - Enter or Space opens the calendar and focuses its chosen day. The calendar's own keys then work: arrows, Page Up and Page Down, Home and End. Escape closes it and returns focus to the trigger.
labelnames the trigger. Without one, passaria-label. Pressing the label moves focus to the trigger without opening the calendar.- Direction is inherited from
dir, never a prop. The calendar takes the page's direction, language and font from the trigger, though it renders at the end ofbody.
Props
DatePicker
| Prop | Type | Default | Description |
|---|---|---|---|
mode | "single" | "range" | "single" | One day, or a range from one day to another. |
value | Date | DateRange | null | — | The chosen day, or the range with mode="range". Use it with onValueChange. |
defaultValue | Date | DateRange | null | — | The value chosen on first render. |
onValueChange | (value) => void | — | Called with the new day, or the range at each end. |
placeholder | ReactNode | — | Text shown while no date is chosen. Defaults to Pick a date, or its Arabic on an Arabic page. |
size | "xs" | "sm" | "md" | "lg" | "md" | Field height: 28, 32, 36 or 40px. |
numberOfMonths | number | 1 | How many months the calendar shows side by side. |
calendarProps | CalendarProps | — | More Calendar props: disabled days, the shown month, month and year menus, radius. |
label | ReactNode | — | The field's label, linked to the trigger for you. |
aria-label | string | — | The trigger's accessible name when there is no visible label. |
aria-labelledby | string | — | The id of an element that names the trigger, in place of label. |
labelEnd | ReactNode | — | A short note at the end of the label row, such as Optional. |
description | ReactNode | — | Helper text under the field. A screen reader reads it with the field. |
descriptionEnd | ReactNode | — | A note at the end of the helper row. |
disabled | boolean | false | Disables the field and dims the whole group. |
name | string | — | The name the value is submitted under. |
form | string | — | The id of the form the value is submitted with, when the field sits outside it. |
id | string | — | The trigger's id. |
open | boolean | — | Opens or closes the calendar, when you control it. |
defaultOpen | boolean | false | Opens the calendar on first render. |
onOpenChange | (open) => void | — | Called when the calendar opens or closes. |
collisionAvoidance | { side, align, fallbackAxisSide } | — | How the calendar avoids the window edge. By default it flips above the trigger when there is no room below. |
container | HTMLElement | — | Where the calendar renders. Default body. |
className | string | — | Extra CSS classes for the field group. |
Usage
One day
import { DatePicker } from "@/components/ui/date-picker"
export function DeliveryDate() {
return (
<DatePicker
name="delivery"
label="Delivery date"
description="We deliver between 9am and 5pm."
calendarProps={{ disabled: { before: new Date() } }}
/>
)
}A range
"use client"
import * as React from "react"
import { DatePicker, type DateRange } from "@/components/ui/date-picker"
export function StayDates() {
const [stay, setStay] = React.useState<DateRange | null>(null)
return (
<DatePicker
mode="range"
numberOfMonths={2}
label="Stay"
value={stay}
onValueChange={setStay}
/>
)
}In a form
import { Button } from "@/components/ui/button"
import { DatePicker } from "@/components/ui/date-picker"
export function BirthDateForm() {
return (
<form action="/profile" className="flex flex-col items-start gap-8">
<DatePicker
name="dob"
label="Date of birth"
description="Your date of birth is used to calculate your age."
calendarProps={{
captionLayout: "dropdown",
startMonth: new Date(1926, 0),
endMonth: new Date(),
}}
/>
<Button type="submit">Submit</Button>
</form>
)
}