# Calendar

## Overview

A date picker calendar that renders a monthly grid of selectable days. Built on `react-day-picker`. Almost always used inside a `<Popover>` to provide an accessible date input. Supports single date selection, multiple dates, and date ranges. When `captionLayout="dropdown"` is used, the month/year header renders as interactive selectors with input-styled visuals.

---

## When to Use

- Date input fields (birth date, due date, deadline)
- Date range selectors (start date / end date)
- Any form field that requires calendar-based date selection

## When NOT to Use

- Datetime selection (date + time) — add a time input separately.
- Period selection that doesn't need exact days — use a `<Select>` with "Last 30 days" options.

---

## Props

| Prop              | Type                                                             | Default    | Description                                                                                        |
| ----------------- | ---------------------------------------------------------------- | ---------- | -------------------------------------------------------------------------------------------------- |
| `mode`            | `'single' \| 'multiple' \| 'range'`                              | `'single'` | Selection mode                                                                                     |
| `selected`        | `Date \| Date[] \| DateRange`                                    | —          | Selected date(s)                                                                                   |
| `onSelect`        | `(date) => void`                                                 | —          | Change handler                                                                                     |
| `captionLayout`   | `'label' \| 'dropdown' \| 'dropdown-months' \| 'dropdown-years'` | `'label'`  | Controls how the month/year header is rendered. `'dropdown'` renders both as interactive selectors |
| `buttonVariant`   | `ButtonVariant`                                                  | `'ghost'`  | Variant applied to the prev/next navigation buttons                                                |
| `initialFocus`    | `boolean`                                                        | `false`    | Focuses the calendar on open (required when inside a Popover)                                      |
| `disabled`        | `Matcher \| Matcher[]`                                           | —          | Disable specific dates                                                                             |
| `fromDate`        | `Date`                                                           | —          | Minimum selectable date                                                                            |
| `toDate`          | `Date`                                                           | —          | Maximum selectable date                                                                            |
| `showOutsideDays` | `boolean`                                                        | `true`     | Show days from adjacent months                                                                     |
| `className`       | `string`                                                         | —          | Additional CSS classes                                                                             |

> All other `react-day-picker` props are forwarded as-is.

---

## Examples

### Single Date Picker (in Popover)

```tsx
import { Popover, PopoverContent, PopoverTrigger, Calendar, Button } from 'xertica-ui/ui';
import { CalendarIcon } from 'lucide-react';
import { format } from 'date-fns';
import { useState } from 'react';

const [date, setDate] = useState<Date>();

<Popover>
  <PopoverTrigger asChild>
    <Button variant="outline" className="w-[240px] justify-start gap-2">
      <CalendarIcon className="size-4" />
      {date ? format(date, 'PPP') : 'Pick a date'}
    </Button>
  </PopoverTrigger>
  <PopoverContent className="w-auto p-0" align="start">
    <Calendar mode="single" selected={date} onSelect={setDate} initialFocus />
  </PopoverContent>
</Popover>;
```

### Dropdown Caption (month/year selectors)

When `captionLayout="dropdown"`, the month and year header is replaced by interactive `<select>` elements styled to match inputs — with border, background, focus ring, and border-radius tokens. The trigger button size is controlled independently of the calendar.

```tsx
const triggerSizeClasses = {
  sm: 'h-8 px-2 text-sm',
  md: 'h-10 px-3 text-base',
  lg: 'h-12 px-4 text-base',
};

<Popover>
  <PopoverTrigger asChild>
    <Button
      variant="outline"
      className={cn(
        'w-[240px] justify-start gap-2 rounded-[var(--radius)]',
        triggerSizeClasses['md']
      )}
    >
      <CalendarIcon className="size-4" />
      {date ? format(date, 'PPP') : 'Pick a date'}
    </Button>
  </PopoverTrigger>
  <PopoverContent className="w-auto p-0" align="start">
    <Calendar
      captionLayout="dropdown"
      mode="single"
      selected={date}
      onSelect={setDate}
      initialFocus
    />
  </PopoverContent>
</Popover>;
```

> **Note:** The `size` prop was intentionally kept off the `Calendar` component. Size and border-radius are concerns of the trigger element, not the calendar grid.

### Disable Past Dates

```tsx
<Calendar
  mode="single"
  selected={date}
  onSelect={setDate}
  disabled={{ before: new Date() }}
  initialFocus
/>
```

### Date Range

```tsx
const [range, setRange] = useState<{ from: Date; to?: Date }>();

<Calendar mode="range" selected={range} onSelect={setRange} className="rounded-md border" />;
```

---

## AI Rules

- Always use Calendar inside a `<Popover>` with `<PopoverContent className="w-auto p-0">`.
- Always pass `initialFocus` when inside a Popover — essential for keyboard/accessibility UX.
- Use `date-fns` for date formatting (`format(date, 'PPP')`) — it is a standard peer dependency.
- For form integration, use the `selected`/`onSelect` pattern, not `{...field}`.
- To control trigger button size and border-radius, apply classes directly on the `<Button>` trigger — do not look for a `size` prop on `<Calendar>`.
- Use `captionLayout="dropdown"` when the user needs to navigate to a distant month/year quickly (e.g., birth date fields).

---

## Related Components

- [`Popover`](./popover.md) — Always wraps Calendar for date input use cases
- [`Select`](./select.md) — Alternative for period/range selection without exact dates
