# Date Picker

A field that opens a calendar to pick a date or a range of dates.

Source: [date-picker.tsx](https://github.com/jakejarvis/jarvis-ui/blob/main/src/components/ui/date-picker.tsx)

```tsx
import { DatePicker, DatePickerContent, DatePickerTrigger } from "@/components/ui/date-picker";

export default function DatePickerBasic() {
  return (
    <DatePicker>
      <DatePickerTrigger aria-label="Due date" className="w-44" />
      <DatePickerContent />
    </DatePicker>
  );
}
```

## Installation

Add the registry, once per project:

```bash
npx shadcn@latest registry add @jarvis=https://ui.jarv.is/r/{name}.json
```

Then add the component:

```bash
npx shadcn@latest add @jarvis/date-picker
```

## Usage

```tsx
import * as React from "react";

import { DatePicker, DatePickerContent, DatePickerTrigger } from "@/components/ui/date-picker";

export function DueDatePicker() {
  const [date, setDate] = React.useState<Date | null>(null);

  return (
    <DatePicker value={date} onValueChange={setDate}>
      <DatePickerTrigger aria-label="Due date" />
      <DatePickerContent />
    </DatePicker>
  );
}
```

`DatePickerTrigger` shows the date, or its `placeholder` while there's none. Give it children to
format the date yourself. `DatePickerContent` opens a [Calendar](https://ui.jarv.is/components/calendar.md) and takes its
props.

## Composition

- `DatePicker`
  - `DatePickerTrigger`
  - `DatePickerContent`

## Examples

### With a label

Point a `FieldLabel` at the trigger's `id`. Without a visible label, give the trigger an
`aria-label`.

```tsx
import { DatePicker, DatePickerContent, DatePickerTrigger } from "@/components/ui/date-picker";
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field";

export default function DatePickerWithLabel() {
  return (
    <Field className="w-full max-w-sm">
      <FieldLabel htmlFor="launch-date">Launch date</FieldLabel>
      <DatePicker defaultValue={new Date(2025, 5, 12)}>
        <DatePickerTrigger id="launch-date" className="w-full" />
        <DatePickerContent />
      </DatePicker>
      <FieldDescription>The release goes out at 9:00 that morning.</FieldDescription>
    </Field>
  );
}
```

### Range

With `mode="range"`, the value is a `{ from, to }` range. `numberOfMonths={2}` on the content shows
two months at once.

```tsx
import { DatePicker, DatePickerContent, DatePickerTrigger } from "@/components/ui/date-picker";

export default function DatePickerRange() {
  return (
    <DatePicker
      mode="range"
      defaultValue={{ from: new Date(2025, 5, 26), to: new Date(2025, 6, 4) }}
    >
      <DatePickerTrigger aria-label="Trip dates" placeholder="Pick dates" className="w-60" />
      <DatePickerContent numberOfMonths={2} showOutsideDays={false} />
    </DatePicker>
  );
}
```

### Month and year dropdowns

For dates far from now, such as a birthday, `captionLayout="dropdown"` adds month and year menus.
Bound them with `startMonth` and `endMonth`.

```tsx
import { DatePicker, DatePickerContent, DatePickerTrigger } from "@/components/ui/date-picker";
import { Field, FieldLabel } from "@/components/ui/field";

const today = new Date();

export default function DatePickerDropdowns() {
  return (
    <Field className="w-48">
      <FieldLabel htmlFor="birthday">Date of birth</FieldLabel>
      <DatePicker>
        <DatePickerTrigger id="birthday" />
        <DatePickerContent
          captionLayout="dropdown"
          defaultMonth={new Date(1990, 0)}
          startMonth={new Date(1930, 0)}
          endMonth={today}
        />
      </DatePicker>
    </Field>
  );
}
```

### Disabled days

Pass `disabled` matchers to the content to rule out days.

```tsx
import { DatePicker, DatePickerContent, DatePickerTrigger } from "@/components/ui/date-picker";
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field";

const today = new Date();

export default function DatePickerDisabledDays() {
  return (
    <Field className="w-48">
      <FieldLabel htmlFor="delivery-date">Delivery date</FieldLabel>
      <DatePicker>
        <DatePickerTrigger id="delivery-date" />
        <DatePickerContent disabled={[{ before: today }, { dayOfWeek: [0, 6] }]} />
      </DatePicker>
      <FieldDescription>We deliver on weekdays.</FieldDescription>
    </Field>
  );
}
```

### In a form

Give a `Field` or the picker a `name`, and the value submits under it: a date as `YYYY-MM-DD`, and
a range as `YYYY-MM-DD/YYYY-MM-DD`, an ISO 8601 interval. Pass `form` with a form's `id` when the
picker sits outside it. With `required`, the form won't submit without a date, or a range with
both its ends, which fails as `valueMissing`. A form reset brings back `defaultValue`.

```tsx
import { Button } from "@/components/ui/button";
import { DatePicker, DatePickerContent, DatePickerTrigger } from "@/components/ui/date-picker";
import { Field, FieldDescription, FieldError, FieldLabel } from "@/components/ui/field";
import { Form } from "@/components/ui/form";
import { toast } from "@/components/ui/toast";

export default function DatePickerForm() {
  return (
    <Form
      className="max-w-sm"
      onFormSubmit={(values) =>
        toast.add({ title: "Stay booked", description: `For ${values.stay}.` })
      }
    >
      <Field name="stay">
        <FieldLabel>Stay</FieldLabel>
        <DatePicker mode="range" required>
          <DatePickerTrigger placeholder="Pick your dates" className="w-full" />
          <DatePickerContent numberOfMonths={2} />
        </DatePicker>
        <FieldDescription>Check in and check out.</FieldDescription>
        <FieldError match="valueMissing">Choose the dates of your stay.</FieldError>
      </Field>
      <Button type="submit" variant="primary" className="self-start">
        Book stay
      </Button>
    </Form>
  );
}
```

### Sizes

`size` on the trigger matches the sizes of buttons, inputs and selects.

```tsx
import { DatePicker, DatePickerContent, DatePickerTrigger } from "@/components/ui/date-picker";

const sizes = ["sm", "default", "lg"] as const;

export default function DatePickerSizes() {
  return (
    <div className="flex flex-wrap items-center gap-3">
      {sizes.map((size) => (
        <DatePicker key={size} defaultValue={new Date(2025, 5, 12)}>
          <DatePickerTrigger size={size} aria-label={`Date, ${size}`} />
          <DatePickerContent />
        </DatePicker>
      ))}
    </div>
  );
}
```

### Invalid

Set `invalid` on the `Field`, and explain the problem with a `FieldError`. The trigger reads out
the field's `FieldDescription` and `FieldError`, and turns invalid or disabled with the field.

```tsx
import { DatePicker, DatePickerContent, DatePickerTrigger } from "@/components/ui/date-picker";
import { Field, FieldError, FieldLabel } from "@/components/ui/field";

export default function DatePickerInvalid() {
  return (
    <Field invalid className="w-48">
      <FieldLabel htmlFor="start-date">Start date</FieldLabel>
      <DatePicker>
        <DatePickerTrigger id="start-date" />
        <DatePickerContent />
      </DatePicker>
      <FieldError>Choose when the contract starts.</FieldError>
    </Field>
  );
}
```

## Props

`DatePickerContent` takes [DayPicker's props](https://daypicker.dev/api/type-aliases/DayPickerProps)
other than the selection ones, plus `side`, `sideOffset`, `align` and `alignOffset`.

| Part | Extends |
| --- | --- |
| `DatePicker` | [`Popover.Root`](https://base-ui.com/react/components/popover#root) |
| `DatePickerTrigger` | [`Popover.Trigger`](https://base-ui.com/react/components/popover#trigger) |
| `DatePickerContent` | `PropsBase` |

The tables leave out `className`, `style` and `render`. Parts built on Base UI take them as its [styling](https://base-ui.com/react/handbook/styling) and [composition](https://base-ui.com/react/handbook/composition) guides describe.

### DatePicker

| Prop                    | Type                                                                       | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| ----------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `defaultOpen?`          | `boolean`                                                                  | Whether the popover is initially open. To render a controlled popover, use the `open` prop instead. Default: `false`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `open?`                 | `boolean`                                                                  | Whether the popover is currently open.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `onOpenChange?`         | `((open: boolean, eventDetails: Popover.Root.ChangeEventDetails) => void)` | Event handler called when the popover is opened or closed.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| `onOpenChangeComplete?` | `((open: boolean) => void)`                                                | Event handler called after any animations complete when the popover is opened or closed.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| `actionsRef?`           | `React.RefObject<PopoverRootActions \| null>`                              | A ref to imperative actions. - `unmount`: Ends the closing phase of the popover after an externally controlled closing animation finishes. Call `preventUnmountOnClose()` in `onOpenChange` first, otherwise the popover completes closing on its own. Whether it leaves the DOM is decided by `keepMounted` on the portal. - `close`: Closes the popover imperatively when called.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `modal?`                | `"trap-focus" \| boolean`                                                  | Determines if the popover enters a modal state when open. - `true`: user interaction is limited to the popover: document page scroll is locked, and pointer interactions on outside elements are disabled. - `false`: user interaction with the rest of the document is allowed. - `'trap-focus'`: focus is trapped inside the popover, but document page scroll is not locked and pointer interactions outside of it remain enabled. On touch devices, a `true` modal blocks outside taps but leaves the page scrollable unless the popup spans nearly the full viewport width, matching native iOS behavior. When `modal` is `true`, focus trapping is enabled only if `<Popover.Close>` is rendered inside `<Popover.Popup>`. It can be visually hidden with your own CSS if needed, such as Tailwind's `sr-only` utility. When `modal` is `'trap-focus'`, render `<Popover.Close>` inside `<Popover.Popup>` so touch screen readers can escape the popup. Default: `false` |
| `triggerId?`            | `string \| null`                                                           | ID of the trigger that the popover is associated with. This is useful in conjunction with the `open` prop to create a controlled popover. There's no need to specify this prop when the popover is uncontrolled (that is, when the `open` prop is not set).                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `defaultTriggerId?`     | `string \| null`                                                           | ID of the trigger that the popover is associated with. This is useful in conjunction with the `defaultOpen` prop to create an initially open popover.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |
| `handle?`               | `Popover.Handle<unknown>`                                                  | A handle to associate the popover with a trigger. If specified, allows external triggers to control the popover's open state.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| `children?`             | `PayloadChildRenderFunction<unknown> \| React.ReactNode`                   | The content of the popover. This can be a regular React node or a render function that receives the `payload` of the active trigger.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `mode?`                 | `"range" \| "single"`                                                      | Whether people pick one date, or a range from a start date to an end date. Default: `"single"`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `value?`                | `Date \| DateRange \| null`                                                | The picked date, or range for `mode="range"`. `null` when there's none.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `defaultValue?`         | `Date \| DateRange \| null`                                                | Default: `null`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `onValueChange?`        | `((value: Date \| DateRange \| null) => void)`                             | Called once a date is picked, or once a range has both its ends, and with `defaultValue` when the picker's form resets.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `locale?`               | `Partial<DayPickerLocale>`                                                 | A DayPicker locale, for the calendar and the date shown on the trigger.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| `name?`                 | `string`                                                                   | Submits the value with a form under this name: a date as `YYYY-MM-DD`, and a range as `YYYY-MM-DD/YYYY-MM-DD`.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `form?`                 | `string`                                                                   | The `id` of the form to submit the value with, when the picker isn't inside it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| `required?`             | `boolean`                                                                  | Whether a form can't be submitted without a date, or a range with both its ends. Default: `false`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |

### DatePickerTrigger

| Prop            | Type                        | Description                                                                                                                                                                                                                                                                                                                                                                 |
| --------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `nativeButton?` | `boolean`                   | Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (for example, `<div>`). Whether the component renders a native `<button>` element when replacing it via the `render` prop. Set to `false` if the rendered element is not a button (e.g. `<div>`). Default: `true` |
| `id?`           | `string`                    | ID of the trigger. In addition to being forwarded to the rendered element, it is also used to specify the active trigger for the popover in controlled mode (with the PopoverRoot `triggerId` prop).                                                                                                                                                                        |
| `handle?`       | `Popover.Handle<unknown>`   | A handle to associate the trigger with a popover.                                                                                                                                                                                                                                                                                                                           |
| `payload?`      | `unknown`                   | A payload to pass to the popover when it is opened.                                                                                                                                                                                                                                                                                                                         |
| `openOnHover?`  | `boolean`                   | Whether the popover should also open when the trigger is hovered. Default: `false`                                                                                                                                                                                                                                                                                          |
| `delay?`        | `number`                    | How long to wait before the popover may be opened on hover. Specified in milliseconds. Requires the `openOnHover` prop. Default: `300`                                                                                                                                                                                                                                      |
| `closeDelay?`   | `number`                    | How long to wait before closing the popover that was opened on hover. Specified in milliseconds. Requires the `openOnHover` prop. Default: `0`                                                                                                                                                                                                                              |
| `size?`         | `"default" \| "lg" \| "sm"` | Default: `"default"`                                                                                                                                                                                                                                                                                                                                                        |
| `placeholder?`  | `string`                    | Shown while there's no date. Default: `"Pick a date"`                                                                                                                                                                                                                                                                                                                       |

### DatePickerContent

| Prop           | Type                                                                       | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| -------------- | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `side?`        | `"bottom" \| "inline-end" \| "inline-start" \| "left" \| "right" \| "top"` | Which side of the anchor element to align the popup against. May automatically change to avoid collisions. Default: `"bottom"`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `sideOffset?`  | `number \| OffsetFunction`                                                 | Distance between the anchor and the popup in pixels. Also accepts a function that returns the distance to read the dimensions of the anchor and positioner elements, along with its side and alignment. The function takes a `data` object parameter with the following properties: - `data.anchor`: the dimensions of the anchor element with properties `width` and `height`. - `data.positioner`: the dimensions of the positioner element with properties `width` and `height`. - `data.side`: which side of the anchor element the positioner is aligned against. - `data.align`: how the positioner is aligned relative to the specified side. Default: `4` |
| `align?`       | `"center" \| "end" \| "start"`                                             | How to align the popup relative to the specified side. Default: `"start"`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `alignOffset?` | `number \| OffsetFunction`                                                 | Additional offset along the alignment axis in pixels. Also accepts a function that returns the offset to read the dimensions of the anchor and positioner elements, along with its side and alignment. The function takes a `data` object parameter with the following properties: - `data.anchor`: the dimensions of the anchor element with properties `width` and `height`. - `data.positioner`: the dimensions of the positioner element with properties `width` and `height`. - `data.side`: which side of the anchor element the positioner is aligned against. - `data.align`: how the positioner is aligned relative to the specified side. Default: `0`  |
