# DatePicker

A field-looking trigger that opens a Calendar in a popover, for picking one date or a range of dates in a form. It takes the same value props as Calendar.

## Usage

### When to use

- Picking one date in a form, next to other fields, with the same field look as Input.
- Limiting the choice to real dates, with disabled days or a min and max date.

### When not to use

- A whole month on the page when the date is the point of the screen. Use Calendar.
- Entering a date as text, such as a birth date the user knows by heart. Use Input.

## Variants

### mode

single picks one Date; range picks a start and an end ({ from, to }) and closes once both are picked.

Values: `single`, `range`. Default: `single`.

### weekStartsOn

The first day of the week in the Calendar: 0 Sunday or 1 Monday. Follows the locale when not set.

Values: `0`, `1`. Default: `undefined`.

## Examples

### In a form

The trigger has the field look, and the grid opens in a popover.

```tsx
<DatePicker placeholder="When does it start?" />
```

### Booking dates

A range over two months. The popover stays open after check-in and closes after check-out.

```tsx
<DatePicker mode="range" numberOfMonths={2} placeholder="Check-in to check-out" />
```

## Do and don't

### Do

- Use DatePicker in forms, next to Input fields with the same md size.
- Name it with a Label pointing at its id, and describe it with aria-describedby, like any field.
- Disable days that can never be picked, such as past days or closed days, over a minDate and maxDate.

### Don't

- Don't use it when the date is the whole screen; put a Calendar on the page instead.
- Don't put long text in the trigger; it shows one formatted date or one range.
- Don't use it for dates the user knows by heart, such as a birth date; an Input is faster.

## Props

| Name | Type | Values | Default | Description |
| --- | --- | --- | --- | --- |
| `mode` | `enum` | `single`, `range` | `single` | single picks one Date; range picks a start and an end ({ from, to }) and closes once both are picked. |
| `value` | `string` |  |  | The picked Date, or in range mode the picked range ({ from, to }), when you control it. An explicit undefined clears the selection; omitting value uses internal state. Pair it with onValueChange. |
| `defaultValue` | `string` |  |  | The Date, or in range mode the range, picked on first render, when you don't control it. |
| `onValueChange` | `function` |  |  | Called with the picked Date, or undefined when the user unpicks it. In range mode only with a complete range, or undefined when a one-day range is cleared. |
| `disabled` | `boolean` |  | `false` | true disables the trigger; a function receives a Date and disables single days in the Calendar, such as weekends or past dates. |
| `minDate` | `string` |  |  | No day before this Date can be picked or navigated to. |
| `maxDate` | `string` |  |  | No day after this Date can be picked or navigated to. |
| `locale` | `string` |  |  | A date-fns Locale object for the trigger text and the Calendar's month and weekday names. The default is enUS. |
| `weekStartsOn` | `enum` | `0`, `1` |  | The first day of the week in the Calendar: 0 Sunday or 1 Monday. Follows the locale when not set. |
| `numberOfMonths` | `number` |  | `1` | How many months the Calendar shows, side by side from sm and stacked below it. Use two for ranges that often cross a month. |
| `rangeStartLabel` | `string` |  | `start of range` | Range mode. Added to the start day's accessible name in the Calendar; translate it with the locale. |
| `rangeEndLabel` | `string` |  | `end of range` | Range mode. Added to the end day's accessible name in the Calendar; translate it with the locale. |
| `placeholder` | `string` |  | `Pick a date` | Text shown in the trigger while no date is picked. It also names the dialog when there is no aria-label. |
| `modal` | `boolean` |  | `false` | Whether the open popover blocks interaction with the rest of the page. |

## Anatomy

| Part | Description |
| --- | --- |
| `root` | The trigger button: the same field look as Input md. |
| `icon` | A decorative Tabler Calendar icon at the start, 16px, secondary. |
| `label` | The picked date, formatted long; in range mode both ends in the medium format joined by an en dash (one date for a one-day range); or the placeholder in secondary text. |
| `content` | The Popover that holds a Calendar. |

## Accessibility

Role: `button`

| Keys | Action |
| --- | --- |
| `Space, Enter` | On the trigger, opens the popover and focuses the selected day, or today. |
| `Escape` | Closes the popover and returns focus to the trigger. In range mode a start without an end is dropped and the value is unchanged. |

- The trigger opens a dialog named by aria-label or the placeholder; inside it, the Calendar grid keeps its own keyboard model.
- A picked date closes the dialog and focus returns to the trigger.
- In range mode the popover keeps a draft: it stays open after the start and sends onValueChange only with a complete range (then closes), or with undefined when the user clears a one-day range. A form value is never start-only. Closing with only a start drops it.
- The trigger accepts id, aria-label and aria-describedby, so a Label and a hint can name and describe it like any field.

## Install

```bash
npx shadcn add https://werewolf-ui.vercel.app/r/date-picker.json
```

This also adds `styles/werewolf.css`, the tokens every component uses, and any other component it needs. Import that file once in your root CSS, after `@import "tailwindcss"`, with a path relative to that CSS file (from `app/globals.css` it is `@import "../styles/werewolf.css"`).
