# Calendar
> Calendar component enables users to view and select dates.

## Import

```jsx
import { Calendar } from '@gemini-suite/vera-react';
```

## Examples

### Basic

By default, `Calendar` renders static, visual calendar. It does not include any logic of dates selection.
It may be useful when you want to display data with in calendar view but do not want it to be interactive.

<Callout variant="tip">

`Calendar` component is built on top of [React Day Picker](https://daypicker.dev/).
Majority of the [React Day Picker API](https://daypicker.dev/api) is available to influence the calendar appearance and behaviour.

</Callout>

```jsx
<Calendar />
```

### Single selection

You can use `Calendar` component as a base to create custom date selection experience if [Date Picker component](/components/forms/date-picker]) does not meet your requirements.

To enable single day selection, set `mode` property to `single`. Also, it usually makes sense to make `Calendar` component controlled using `selected` and `onSelect` props.

```jsx
() => {
  const [selected, setSelected] = React.useState(new Date());

  return <Calendar mode="single" selected={selected} onSelect={setSelected} />;
};
```

### Range selection

Set `mode` to `range` to allow the selection of multiple days.

```jsx
() => {
  const [range, setRange] = React.useState({
    from: new Date(2023, 9, 10),
    to: new Date(2023, 9, 19)
  });
  const formatter = useDateFormatter('en', {
    dateStyle: 'medium'
  });

  return (
    <Flex flow="column">
      <Calendar
        mode="range"
        selected={range}
        onSelect={setRange}
        numberOfMonths={2}
        defaultMonth={range?.from}
      />
      <Box>
        {range?.from && range?.to ? (
          <Text fontSize="zeta">
            {formatter.formatRange(range.from, range.to)}
          </Text>
        ) : null}
      </Box>
    </Flex>
  );
};
```

### Min/max date

You can set minimum and/or maximum dates to limit users to choose from a specific period in time.

Use `startMonth` and `endMonth` props to control time frames.

```jsx
() => {
  const today = new Date();
  const [selectedDay, setSelectedDay] = React.useState(today);
  const max = new Date(today.getFullYear() + 1, 11);

  return (
    <Calendar
      mode="single"
      startMonth={today}
      endMonth={max}
      selected={selectedDay}
      onSelect={setSelectedDay}
    />
  );
};
```

### Caption layout

By default `Calendar` can be navigated using buttons for moving forward/backward through months. To enable select dropdowns for choosing the month and the year, use `captionLayout="dropdown"` prop.

The following layouts of the month caption are available:

- `label`: displays the month and year as a label (default).
- `dropdown`: displays dropdowns for choosing the month and the year.
- `dropdown-months`: displays a dropdown with the months only.
- `dropdown-years`: displays a dropdown with the years only.

<Callout variant="tip">

`dropdown` is typically recommended as it lets the user easily find the time period they want to choose from without having to click through months.

</Callout>

<Callout variant="tip">

When explicit time frame is not provided using `startMonth` and `endMonth`, showing the dropdown will set the start year to 100 years ago, and end year to the current year.

</Callout>

```jsx
() => {
  const [selected, setSelected] = React.useState(new Date());

  return (
    <Flex gap="spacingXl" wrap="wrap" cross="start" wrap="wrap">
      <Calendar selected={selected} onSelect={setSelected} />
      <Calendar
        captionLayout="dropdown"
        selected={selected}
        onSelect={setSelected}
        startMonth={new Date(2019, 0)}
        endMonth={new Date(2029, 11)}
      />
    </Flex>
  );
};
```

### Sizes

Calendar component comes in two sizes: `medium` and `small`. By default, it uses `medium` size.

```jsx
() => {
  const [selected, setSelected] = React.useState(new Date());
  const [selectedSmall, setSelectedSmall] = React.useState(new Date());
  const today = new Date();

  return (
    <Flex wrap="wrap" gap="spacingXl" cross="start" wrap="wrap">
      <Calendar
        selected={selected}
        onSelect={setSelected}
        captionLayout="dropdown"
        startMonth={new Date(today.getFullYear() - 5, 0)}
        endMonth={new Date(today.getFullYear() + 5, 11)}
      />
      <Calendar
        size="small"
        selected={selectedSmall}
        onSelect={setSelectedSmall}
        captionLayout="dropdown"
        startMonth={new Date(today.getFullYear() - 5, 0)}
        endMonth={new Date(today.getFullYear() + 5, 11)}
      />
    </Flex>
  );
};
```

### Disabled state

Among other [modifiers that React Day Picker provides](https://daypicker.dev/guides/custom-modifiers#built-in-modifiers), it's convenient to disable specific days in the calendar.
In addition, you can disable the navigation using `disableNavigation` prop or hide it altogether using `hideNavigation` prop.

```jsx
() => {
  const [selectedDay, setSelectedDay] = React.useState(new Date(2023, 9, 10));

  const disabled = [
    new Date(2023, 9, 9),
    new Date(2023, 9, 13),
    { from: new Date(2023, 9, 16), to: new Date(2023, 9, 22) },
    {
      after: new Date(2023, 9, 27)
    }
  ];

  return (
    <Calendar
      mode="single"
      selected={selectedDay}
      onSelect={setSelectedDay}
      defaultMonth={new Date(2023, 9, 1)}
      disabled={disabled}
      disableNavigation
    />
  );
};
```

### Locale

To change the locale, pass to the `locale` prop a [date-fns locale object](https://date-fns.org/docs/Locale).

For example, to localize the calendar in German, import the locale object from [date-fns](https://date-fns.org/) and pass it to the component.

```js
import { de } from 'date-fns/locale';
// import { enGB, nb, ... } from 'date-fns/locale';
```

```jsx
() => {
  const [selectedDay, setSelectedDay] = React.useState(new Date());
  const formatter = useDateFormatter(de.code, {
    day: 'numeric',
    year: 'numeric',
    month: 'long'
  });

  return (
    <Flex flow="column">
      <Calendar
        mode="single"
        locale={de}
        onSelect={setSelectedDay}
        selected={selectedDay}
      />
      <Text fontSize="zeta">{formatter.format(selectedDay)}</Text>
    </Flex>
  );
};
```

### Time zone

To change the time zone, pass [IANA time zone](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones) identifier or a UTC offset to `timeZone` prop.

<Callout variant="important">

When working with time zones, make sure to use `TZDate` object from [date-fns timezone utils](https://date-fns.org/v4.1.0/docs/Time-Zones) instead of the native `Date` object.

</Callout>

```js
import { TZDate } from '@date-fns/tz';
```

```jsx
() => {
  const [timeZone, setTimeZone] = React.useState('Europe/Berlin');
  const [selected, setSelected] = React.useState(
    new TZDate(2024, 09, 10, timeZone) // Make sure you use `TZDate` instead of `Date`
  );

  const handleTimeZoneChange = timeZone => {
    setTimeZone(timeZone);
    setSelected(new TZDate(selected, timeZone));
  };

  return (
    <Flex flow="column" main="start">
      <SingleSelectMenu.Root
        value={timeZone}
        onValueChange={handleTimeZoneChange}
      >
        <SingleSelectMenu.Trigger css={{ maxWidth: 286 }} />
        <SingleSelectMenu.Content>
          <SingleSelectMenu.Item value="-08:00">
            {'-08:00'}
          </SingleSelectMenu.Item>
          <SingleSelectMenu.Item value="Europe/Berlin">
            {'Europe/Berlin'}
          </SingleSelectMenu.Item>
          <SingleSelectMenu.Item value="Asia/Tokyo">
            {'Asia/Tokyo'}
          </SingleSelectMenu.Item>
          <SingleSelectMenu.Item value="UTC">{'UTC'}</SingleSelectMenu.Item>
        </SingleSelectMenu.Content>
      </SingleSelectMenu.Root>
      <Calendar
        mode="single"
        timeZone={timeZone}
        selected={selected}
        onSelect={setSelected}
      />
      <Text fontSize="zeta">
        {selected
          ? selected.toString()
          : `Pick a day to see it in ${timeZone} time zone.`}
      </Text>
    </Flex>
  );
};
```

### Inside popover

Usually `Calendar` component is placed in a wrapping component such as [Card](/components/card) or [Popover](/components/popover).

<Callout variant="tip">

[Date Picker component](/components/forms/date-picker]) is built using a composition of the `Popover` and `Calendar` components.

</Callout>

```jsx
() => {
  const [selected, setSelected] = React.useState(new Date());

  return (
    <Popover.Root>
      <Popover.Trigger as={Button} variant="outline">
        {'Open Calendar'}
      </Popover.Trigger>
      <Popover.Content padding="spacingM">
        <Calendar mode="single" selected={selected} onSelect={setSelected} />
      </Popover.Content>
    </Popover.Root>
  );
};
```

---

## Accessibility features

<ul>
  <li iconName="check">

`Calendar` provides [deep keyboard interactions](https://daypicker.dev/guides/accessibility#keyboard-navigation).

  </li>
  <li iconName="check">

Necessary ARIA roles and attributes are provided to give directions to a screen reader user.

  </li>
</ul>

---

## API Reference

<Callout variant="tip">

The props below show a commonly used subset of [React DayPicker API](https://daypicker.dev/api).

</Callout>

| Name                | Type                                                             | Default    | Description                                                                                                                                                         | Required |
| ------------------- | ---------------------------------------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `mode`              | `"single" \| "range"`                                            |            | Defines the selection mode. The mode affects how `selected` and `onSelect` props are defined.                                                                       |          |
| `size`              | `"medium" \| "small"`                                            | `"medium"` | The size of the calendar.                                                                                                                                           |          |
| `captionLayout`     | `"label" \| "dropdown" \| "dropdown-months" \| "dropdown-years"` | `"label"`  | Controls the layout of the calendar caption.                                                                                                                        |          |
| `selected`          | `Matcher \| Matcher[]`                                           |            | Applies the `selected` modifier to the matching days. [See full prop type definition](https://daypicker.dev/api/type-aliases/Matcher) .                             |          |
| `onSelect`          | `"SelectSingleEventHandler" \| "SelectRangeEventHandler"`        |            | Event fired when day or range is selected.                                                                                                                          |          |
| `className`         | `string`                                                         |            | `className` to add to the calendar.                                                                                                                                 |          |
| `defaultMonth`      | `Date`                                                           |            | The initial month to show in the calendar.                                                                                                                          |          |
| `startMonth`        | `Date`                                                           |            | The earliest month to start the month navigation.                                                                                                                   |          |
| `endMonth`          | `Date`                                                           |            | The latest month to end the month navigation.                                                                                                                       |          |
| `disabled`          | `Matcher \| Matcher[]`                                           |            | Applies the `disabled` modifier to the matching days. [See full prop type definition](https://daypicker.dev/api/type-aliases/Matcher) .                             |          |
| `modifiers`         | `DayModifiers`                                                   |            | Add [modifiers](https://daypicker.dev/guides/custom-modifiers) to the matching days.                                                                                |          |
| `disableNavigation` | `boolean`                                                        |            | When `true`, the navigation between months will be disabled.                                                                                                        |          |
| `hideNavigation`    | `boolean`                                                        |            | When `true`, the navigation between months will be hidden.                                                                                                          |          |
| `numberOfMonths`    | `number`                                                         | `1`        | The number of displayed months.                                                                                                                                     |          |
| `locale`            | `Locale`                                                         |            | The [date-fns locale object](https://date-fns.org/docs/Locale) used to localize the calendar and text input format.                                                 |          |
| `timeZone`          | `string`                                                         |            | Time zone (IANA or UTC offset) for the calendar.                                                                                                                    |          |
| `footer`            | `React.ReactNode`                                                |            | Content to add to the calendar footer.                                                                                                                              |          |
| `labels`            | `Partial<Labels>`                                                |            | Labels creators to override the defaults. Use this prop to customize the ARIA labels attributes.                                                                    |          |
| `showOutsideDays`   | `boolean`                                                        | `true`     | When `true`, outside days will be shown. An outside day is a day falling in the next or the previous month.                                                         |          |
| `today`             | `Date`                                                           |            | The today's date. Default is the current date. This date will get the `today` modifier.                                                                             |          |
| `components`        | `Partial<DayPickerComponents>`                                   |            | Override internal components used for rendering the calendar elements. [See full prop type definition](https://daypicker.dev/api/interfaces/PropsBase#components) . |          |
| `classNames`        | `Partial<DayPickerClassNames>`                                   |            | Override internal class names. [See full prop type definition](https://daypicker.dev/api/interfaces/PropsBase#classnames) .                                         |          |
