---
title: Calendar
description: Date selection calendar with single, multiple, and range modes.
icon: calendar
---

import { ComponentPreview } from '/snippets/component-preview.mdx'

The Calendar component renders a month view for selecting dates. It supports single date, multiple date, and date range selection. Selected dates are stored in client state as ISO strings.

## Basic Usage

<ComponentPreview json={{"view":{"name":"calendar_1","type":"Calendar","mode":"single"}}} playground="ZnJvbSBwcmVmYWJfdWkuY29tcG9uZW50cyBpbXBvcnQgQ2FsZW5kYXIKCkNhbGVuZGFyKCkK">
<CodeGroup>
```python Python icon="python"
from prefab_ui.components import Calendar

Calendar()
```
```json Protocol icon="brackets-curly"
{"view": {"name": "calendar_1", "type": "Calendar", "mode": "single"}}
```
</CodeGroup>
</ComponentPreview>

## Initial Value

Pass a `datetime.date` to `value` to pre-select a date:

<ComponentPreview json={{"view":{"name":"calendar_2","type":"Calendar","mode":"single"},"state":{"calendar_2":"2026-07-04T12:00:00.000Z"}}} playground="aW1wb3J0IGRhdGV0aW1lCmZyb20gcHJlZmFiX3VpLmNvbXBvbmVudHMgaW1wb3J0IENhbGVuZGFyCgpDYWxlbmRhcih2YWx1ZT1kYXRldGltZS5kYXRlKDIwMjYsIDcsIDQpKQo=">
<CodeGroup>
```python Python icon="python"
import datetime
from prefab_ui.components import Calendar

Calendar(value=datetime.date(2026, 7, 4))
```
```json Protocol icon="brackets-curly"
{
  "view": {"name": "calendar_2", "type": "Calendar", "mode": "single"},
  "state": {"calendar_2": "2026-07-04T12:00:00.000Z"}
}
```
</CodeGroup>
</ComponentPreview>

## Range Selection

Set `mode="range"` to let users select a start and end date. The value is a dict with `"from"` and `"to"` keys:

<ComponentPreview json={{"view":{"name":"calendar_3","type":"Calendar","mode":"range"},"state":{"calendar_3":"{\"from\": \"2025-06-10T12:00:00.000Z\", \"to\": \"2025-06-20T12:00:00.000Z\"}"}}} playground="aW1wb3J0IGRhdGV0aW1lCmZyb20gcHJlZmFiX3VpLmNvbXBvbmVudHMgaW1wb3J0IENhbGVuZGFyCgpDYWxlbmRhcigKICAgIG1vZGU9InJhbmdlIiwKICAgIHZhbHVlPXsKICAgICAgICAiZnJvbSI6IGRhdGV0aW1lLmRhdGUoMjAyNSwgNiwgMTApLAogICAgICAgICJ0byI6IGRhdGV0aW1lLmRhdGUoMjAyNSwgNiwgMjApLAogICAgfSwKKQo=">
<CodeGroup>
```python Python icon="python"
import datetime
from prefab_ui.components import Calendar

Calendar(
    mode="range",
    value={
        "from": datetime.date(2025, 6, 10),
        "to": datetime.date(2025, 6, 20),
    },
)
```
```json Protocol icon="brackets-curly"
{
  "view": {"name": "calendar_3", "type": "Calendar", "mode": "range"},
  "state": {
    "calendar_3": "{\"from\": \"2025-06-10T12:00:00.000Z\", \"to\": \"2025-06-20T12:00:00.000Z\"}"
  }
}
```
</CodeGroup>
</ComponentPreview>

## Multiple Selection

Select multiple individual dates with `mode="multiple"`. The value is a list of dates:

<ComponentPreview json={{"view":{"name":"calendar_4","type":"Calendar","mode":"multiple"},"state":{"calendar_4":"[\"2025-06-10T12:00:00.000Z\", \"2025-06-15T12:00:00.000Z\", \"2025-06-22T12:00:00.000Z\"]"}}} playground="aW1wb3J0IGRhdGV0aW1lCmZyb20gcHJlZmFiX3VpLmNvbXBvbmVudHMgaW1wb3J0IENhbGVuZGFyCgpDYWxlbmRhcigKICAgIG1vZGU9Im11bHRpcGxlIiwKICAgIHZhbHVlPVsKICAgICAgICBkYXRldGltZS5kYXRlKDIwMjUsIDYsIDEwKSwKICAgICAgICBkYXRldGltZS5kYXRlKDIwMjUsIDYsIDE1KSwKICAgICAgICBkYXRldGltZS5kYXRlKDIwMjUsIDYsIDIyKSwKICAgIF0sCikK">
<CodeGroup>
```python Python icon="python"
import datetime
from prefab_ui.components import Calendar

Calendar(
    mode="multiple",
    value=[
        datetime.date(2025, 6, 10),
        datetime.date(2025, 6, 15),
        datetime.date(2025, 6, 22),
    ],
)
```
```json Protocol icon="brackets-curly"
{
  "view": {"name": "calendar_4", "type": "Calendar", "mode": "multiple"},
  "state": {
    "calendar_4": "[\"2025-06-10T12:00:00.000Z\", \"2025-06-15T12:00:00.000Z\", \"2025-06-22T12:00:00.000Z\"]"
  }
}
```
</CodeGroup>
</ComponentPreview>

## Reading the Value

Use `.rx` to get a reactive reference to the calendar's current selection. What `.rx` holds depends on the mode: an ISO date string for single mode, a `{"from": ..., "to": ...}` object for range mode, or an array of ISO strings for multiple mode. The `.date()` pipe formats a single ISO string for display:

<ComponentPreview json={{"view":{"cssClass":"gap-6","type":"Row","children":[{"name":"calendar_5","type":"Calendar","mode":"single"},{"cssClass":"gap-2 justify-center","type":"Column","children":[{"type":"Label","text":"Selected date"},{"name":"input_1","type":"Input","inputType":"text","value":"{{ calendar_5 | date:long }}","disabled":false,"readOnly":true,"required":false}]}]},"state":{"calendar_5":"2026-07-04T12:00:00.000Z"}}} playground="aW1wb3J0IGRhdGV0aW1lCmZyb20gcHJlZmFiX3VpLmNvbXBvbmVudHMgaW1wb3J0IENhbGVuZGFyLCBDb2x1bW4sIElucHV0LCBMYWJlbCwgUm93Cgp3aXRoIFJvdyhnYXA9Nik6CiAgICBjYWwgPSBDYWxlbmRhcih2YWx1ZT1kYXRldGltZS5kYXRlKDIwMjYsIDcsIDQpKQogICAgd2l0aCBDb2x1bW4oZ2FwPTIsIGp1c3RpZnk9ImNlbnRlciIpOgogICAgICAgIExhYmVsKCJTZWxlY3RlZCBkYXRlIikKICAgICAgICBJbnB1dCh2YWx1ZT1jYWwucnguZGF0ZSgibG9uZyIpLCByZWFkX29ubHk9VHJ1ZSkK">
<CodeGroup>
```python Python icon="python"
import datetime
from prefab_ui.components import Calendar, Column, Input, Label, Row

with Row(gap=6):
    cal = Calendar(value=datetime.date(2026, 7, 4))
    with Column(gap=2, justify="center"):
        Label("Selected date")
        Input(value=cal.rx.date("long"), read_only=True)
```
```json Protocol icon="brackets-curly"
{
  "view": {
    "cssClass": "gap-6",
    "type": "Row",
    "children": [
      {"name": "calendar_5", "type": "Calendar", "mode": "single"},
      {
        "cssClass": "gap-2 justify-center",
        "type": "Column",
        "children": [
          {"type": "Label", "text": "Selected date"},
          {
            "name": "input_1",
            "type": "Input",
            "inputType": "text",
            "value": "{{ calendar_5 | date:long }}",
            "disabled": false,
            "readOnly": true,
            "required": false
          }
        ]
      }
    ]
  },
  "state": {"calendar_5": "2026-07-04T12:00:00.000Z"}
}
```
</CodeGroup>
</ComponentPreview>

Click a date and the input updates instantly. The `.date("long")` pipe formats an ISO string like `"2025-01-15"` into `"January 15, 2025"`.

## API Reference

<Card icon="code" title="Calendar Parameters">
<ParamField body="mode" type="str" default="single">
  Selection mode: `"single"`, `"multiple"`, or `"range"`.
</ParamField>

<ParamField body="value" type="date | Rx | dict | list[date] | None" default="None">
  Initial selected date(s). Single: a `datetime.date`. Range: `{"from": date, "to": date}`. Multiple: a list of dates. Any position also accepts an `Rx` for reactive binding.
</ParamField>

<ParamField body="name" type="str | None" default="None">
  State key for storing the selected date. Single mode stores an ISO string; range mode stores `{"from": "...", "to": "..."}`.
</ParamField>

<ParamField body="on_change" type="Action | list[Action] | None" default="None">
  Action(s) triggered when the selection changes.
</ParamField>

<ParamField body="css_class" type="str | None" default="None">
  Additional Tailwind CSS classes.
</ParamField>
</Card>

## Protocol Reference

```json Calendar
{
  "type": "Calendar",
  "mode?": "single | multiple | range",
  "name?": "string",
  "onChange?": "Action | Action[]",
  "cssClass?": "string"
}
```

For the complete protocol schema, see [Calendar](/protocol/calendar).
