# Calendar

A month of days to pick one from. Days follow the locale: month and weekday names, the first day of the week and the digits. Nothing is selected until the person picks a day; today is outlined, not selected. A day you mark `unavailable` stays reachable by keyboard, is `aria-disabled`, and says why (needs a `TooltipProvider`).

Keyboard: arrow keys move by a day or a week, Home and End to the start and end of the week, Page Up and Page Down by a month (with Shift by a year), Enter or Space selects. A day is a calendar date, not an instant.

- Registry name: `calendar` (`@candor/calendar`)
- Tier: Pro. Installing it needs a Pro, Premium or Team licence key: the person runs `npx candor-ui key <key>` themselves; never ask for the key in chat or write it to a file.
- Docs: https://candor.themethodic.com/docs/calendar

## Install

```bash
npx candor-ui add calendar
```

Run `npx candor-ui@latest init` once first (https://candor.themethodic.com/get-started.md). Without the CLI: `npx shadcn@latest add @candor/calendar`.
It brings in: button, locale, locked, utils.
npm packages: lucide-react@^1.67.0.

## Example

```tsx
"use client"

import * as React from "react"
import { Calendar, useDayFormat } from "@/components/ui/calendar"

// Weekends are closed for deploys here, and each closed day says so. Nothing is selected until a day is picked.
export default function Example() {
  const [day, setDay] = React.useState<Date | undefined>()
  const format = useDayFormat()
  return (
    <div className="flex flex-col items-start gap-3">
      <Calendar
        defaultMonth={new Date(2026, 10, 1)}
        today={new Date(2026, 10, 8)}
        value={day ?? null}
        onValueChange={setDay}
        unavailable={(d) => (d.getDay() === 0 || d.getDay() === 6 ? "No deploys at weekends." : null)}
        label="Deploy date"
      />
      <p className="text-sm text-muted-foreground">{day ? `Deploy on ${format(day, "full")}.` : "Pick a weekday."}</p>
    </div>
  )
}
```

## <Calendar>

Props:

- `value?: Date | null | undefined`: The selected day, when you control it. `null` is nothing selected.
- `defaultValue?: Date | undefined`: The day selected at first, when you don't control it. Left out, no day is selected.
- `onValueChange?: ((date: Date) => void) | undefined`: Called with the day a person picks (at local midnight).
- `month?: Date | undefined`: The month shown, when you control it; any day in it.
- `defaultMonth?: Date | undefined`: The month shown at first: any day in it. Defaults to the selected day's month, else today's. Set it for server rendering, so the server and browser agree.
- `onMonthChange?: ((month: Date) => void) | undefined`: Called with the first of the month a person moves to.
- `unavailable?: ((date: Date) => string | null | undefined | false) | undefined`: Returns why a day can't be picked, or nothing when it can. The reason is shown to everyone, never swallowed.
- `weekStartsOn?: number | undefined`: The first day of the week, 0 (Sunday) to 6. Defaults to the locale's.
- `today?: Date | undefined`: The day to outline as today. Left out, the browser's today once the page has hydrated.
- `label?: string | undefined`: The grid's accessible name besides the month. Defaults to "Calendar".
- `className?: string | undefined`

## Functions

### useDayFormat

```ts
useDayFormat()
```

Formats a calendar day in the locale: "8 Nov 2026". A day here is the date on the wall, not an instant, so this ignores `LocaleProvider`'s time zone; a `Date` built from `new Date(2026, 10, 8)` reads as 8 November everywhere.

## Strings (`calendar`)

The fixed words, English by default. Override any of them under `calendar` in `<LocaleProvider strings={{ calendar: { … } }}>`; the table is exported as `calendarStrings`.

- `label`: Calendar
- `previousMonth`: Previous month
- `nextMonth`: Next month

## Motion

- **tint** (tint): A day's background changes when the pointer is over it, and a ring fades in when it takes keyboard focus. The selected day's colours change when the person picks another day; a day that is selected when the calendar appears is drawn selected at once.

Set with `--cd-motion-calendar-<moment>-*` in your brand file; the families are in the design reference.

## Rules for using Candor UI

- Components take plain typed data. Never pass model output as HTML or render it as a link; messages are typed blocks.
- A control that can't be used says why: wrap it in `<Locked reason="…">`, don't just disable it.
- Don't show a value you don't have: leave it out (it renders as —) rather than guess. An estimate is labelled as one.
- Nothing is pre-selected in a decision a person makes, and the agent is named from your app's data, never from model output.
- Your app's words go in `LocaleProvider` (fixed strings) and `TermsProvider` (nouns); entity kinds and agent roles in `EntityKindsProvider` and `AgentRolesProvider`.
