# Calendar

> Month-view calendar — standalone widget for picking a single date or a date range. Built on the `WrDateAdapter` abstraction. Click the header label to zoom into month / year quick-pick views.

Source: https://ngwr.dev/reference/components/calendar  
Kind: a11y

## Installation

```angular-ts
import { WrCalendar } from 'ngwr/calendar';
import { provideWrDateAdapter } from 'ngwr/date';

// In main.ts
bootstrapApplication(AppComponent, {
  providers: [provideWrDateAdapter()],
});

// In any component
@Component({ imports: [WrCalendar] })
export class MyComponent {
  protected readonly picked = signal<Date | null>(new Date());
}
```

## Single date

Default mode. Two-way bind a `Date` (or `null`).

```angular-html
<wr-calendar [(date)]="picked" />
```

## Date range

Set `mode="range"` and bind `[(range)]` to a `[start, end]` tuple. Hovering after picking the start previews the would-be selection.

```angular-html
<wr-calendar mode="range" [(range)]="picked" />
```

## Bounds + filter

`min` / `max` clamp the selectable range; `dateFilter` is a predicate that disables individual dates (here: only weekdays).

```angular-html
<wr-calendar
  [(date)]="picked"
  [min]="firstOfYear"
  [max]="lastOfYear"
  [dateFilter]="isWeekday"
/>
```

## Keyboard

The grid is a SINGLE tab stop with a roving cursor — tabbing through a month is not 42 stops — so exactly one cell is tabbable at a time and the arrows move it. The header's `‹` / `›` buttons and the month/year label are separate, ordinary tab stops before it.

| Key | Does |
| --- | --- |
| ArrowLeftArrowRight | Previous / next day. The pair swaps under `dir="rtl"` — these name a side of the screen. |
| ArrowUpArrowDown | Same weekday, one week back / forward. |
| HomeEnd | First / last day of the current week — which respects the adapter's first day of the week, not Sunday. |
| PageUpPageDown | Previous / next month, scrolling the view with it. |
| Shift + PageUpShift + PageDown | Previous / next year. |
| EnterSpace | Picks the day under the cursor — the same commit as a click, including the second click of a range. |

| Key | Does |
| --- | --- |
| ArrowLeftArrowRight | Previous / next chip, mirrored under `dir="rtl"`. |
| ArrowUpArrowDown | One full row: three chips in the month view, four in the year view. |
| HomeEnd | First / last chip on the page. The list does not wrap or spill into the next twelve — the header's `‹` / `›` are what change which twelve. |
| EnterSpace | Left to the browser: each chip is a real `<button>`. |

**A cursor never parks on a day it cannot pick.** With `[min]`, `[max]` or `[dateFilter]` in play, a keystroke that lands on a disabled cell keeps travelling in the direction it was already going, and stops only when the run does. Not cosmetic: the cursor cell holds the grid's only `tabindex="0"`, so parking it on a disabled button would leave the calendar with zero tabbable cells — you could tab out of it and never tab back in.

## API

| Name | Description | Type | Default |
| --- | --- | --- | --- |
| `mode` | Selection mode. | `WrCalendarMode` | `'single'` |
| `date` | Two-way bindable single value (used when `mode === 'single'`). | `Date \| null` | `null` |
| `range` | Two-way bindable `[start, end]` (used when `mode === 'range'`). | `WrCalendarRange` | `[null, null]` |
| `min` | Min selectable date (inclusive). | `Date \| null` | `null` |
| `max` | Max selectable date (inclusive). | `Date \| null` | `null` |
| `dateFilter` | Predicate — return `false` to disable specific dates (e.g. weekends only). | `((date: Date) => boolean) \| null` | `null` |
| `autoFocus` | Move real focus onto the roving cell as soon as the grid is on screen. Off by default: a standalone `<wr-calendar>` sitting in a page must not steal focus on load. `wr-date-picker` turns it on for the popup it opens from its trigger, where the user asked to be taken to the calendar. | `boolean` | `false` |
| `disabled` | Disable interaction entirely. | `boolean` | `false` |

## CSS variables

Custom properties `ngwr/calendar` publishes. Each default below is declared on the component's own selector, so a `:root` override is shadowed by it — set them on that selector, on a wrapper you scope yourself, or inline on the element. Unlike the BEM class names, these are the supported way to restyle the component.

| Variable | Default | Declared on |
| --- | --- | --- |
| `--wr-calendar-accent` | `var(--wr-color-primary)` | `.wr-calendar` |
| `--wr-calendar-accent-contrast` | `var(--wr-color-primary-contrast)` | `.wr-calendar` |
| `--wr-calendar-accent-ink` | `var(--wr-color-primary-ink)` | `.wr-calendar` |
| `--wr-calendar-accent-rgb` | `var(--wr-color-primary-rgb)` | `.wr-calendar` |
| `--wr-calendar-bg` | `var(--wr-color-surface)` | `.wr-calendar` |
| `--wr-calendar-border` | `var(--wr-color-outline)` | `.wr-calendar` |
| `--wr-calendar-cell-size` | `2rem` | `.wr-calendar` |
| `--wr-calendar-color` | `var(--wr-color-on-surface)` | `.wr-calendar` |
| `--wr-calendar-day-radius` | `var(--wr-border-radius-sm)` | `.wr-calendar` |
| `--wr-calendar-muted` | `var(--wr-color-on-surface-muted)` | `.wr-calendar` |
| `--wr-calendar-radius` | `var(--wr-border-radius-base)` | `.wr-calendar` |
| `--wr-calendar-width` | `17rem` | `.wr-calendar` |
