---
title: Calendar
description: A calendar component that allows users to select a date or a range of dates.
---

```templ
package examples

import (
	"time"

	"github.com/axadrn/shadcn-templ/v2/components/calendar"
)

templ CalendarDemo() {
	{{ now := time.Now() }}
	@calendar.Calendar(calendar.Props{
		Selected:         now,
		CaptionLayout: calendar.CaptionLayoutDropdown,
		Class:         "rounded-lg border",
	})
}
```

## Installation

<CodeTabs>

<TabsList>
  <TabsTrigger value="cli">Command</TabsTrigger>
  <TabsTrigger value="manual">Manual</TabsTrigger>
</TabsList>
<TabsContent value="cli">

```bash
shadcn-templ add calendar
```

</TabsContent>

<TabsContent value="manual">

<Steps className="mb-0 pt-2">

<Step>Copy and paste the following code into your project.</Step>

<ComponentSource name="calendar" title="components/calendar/calendar.templ" />

<ComponentSource name="calendar" title="components/calendar/calendar.js" />

Component scripts are loaded through the shared script bundle, see [JavaScript](/docs/installation#javascript).

<Step>Update the import paths to match your project setup.</Step>

</Steps>

</TabsContent>

</CodeTabs>

## Usage

```go showLineNumbers
import (
	"time"

	"github.com/axadrn/shadcn-templ/v2/components/calendar"
)
```

```templ showLineNumbers
@calendar.Calendar(calendar.Props{
	Selected: time.Now(),
	Class: "rounded-lg border",
})
```

## About

The `Calendar` component is a native templ and vanilla JavaScript implementation with no external dependencies.

## Date Picker

You can use the `Calendar` component to build a date picker. See the [Date Picker](/docs/components/date-picker) page for more information.

## Basic

A basic calendar component. We used `Class: "rounded-lg border"` to style the calendar.

```templ
package examples

import "github.com/axadrn/shadcn-templ/v2/components/calendar"

templ CalendarBasic() {
	@calendar.Calendar(calendar.Props{Class: "rounded-lg border"})
}
```

## Range Calendar

Use the `Mode: calendar.ModeRange` prop to enable range selection.

```templ
package examples

import (
	"time"

	"github.com/axadrn/shadcn-templ/v2/components/calendar"
)

templ CalendarRange() {
	{{
		from := time.Date(time.Now().Year(), 1, 12, 0, 0, 0, 0, time.Local)
		to := from.AddDate(0, 0, 30)
	}}
	@calendar.Calendar(calendar.Props{
		Mode:           calendar.ModeRange,
		Selected:          from,
		EndValue:       to,
		NumberOfMonths: 2,
		Class:          "rounded-lg border",
	})
}
```

## Month and Year Selector

Use `CaptionLayout: calendar.CaptionLayoutDropdown` to show month and year dropdowns.

```templ
package examples

import "github.com/axadrn/shadcn-templ/v2/components/calendar"

templ CalendarCaption() {
	@calendar.Calendar(calendar.Props{
		CaptionLayout: calendar.CaptionLayoutDropdown,
		Class:         "rounded-lg border",
	})
}
```

## Presets

```templ
package examples

import (
	"time"

	"github.com/axadrn/shadcn-templ/v2/components/button"
	"github.com/axadrn/shadcn-templ/v2/components/calendar"
	"github.com/axadrn/shadcn-templ/v2/components/card"
)

templ CalendarPresets() {
	{{ selected := time.Date(time.Now().Year(), 2, 12, 0, 0, 0, 0, time.Local) }}
	{{
		presets := []struct {
			Label string
			Days  string
		}{
			{"Today", "0"},
			{"Tomorrow", "1"},
			{"In 3 days", "3"},
			{"In a week", "7"},
			{"In 2 weeks", "14"},
		}
	}}
	@card.Card(card.Props{
		Size:  card.SizeSm,
		Class: "mx-auto w-fit max-w-[300px]",
	}) {
		@card.Content() {
			@calendar.Calendar(calendar.Props{
				ID:         "calendar-presets",
				Selected:      selected,
				FixedWeeks: true,
				Class:      "p-0 [--cell-size:--spacing(9.5)]",
			})
		}
		@card.Footer(card.FooterProps{Class: "flex flex-wrap gap-2 border-t"}) {
			for _, preset := range presets {
				@button.Button(button.Props{
					Variant: button.VariantOutline,
					Size:    button.SizeSm,
					Class:   "flex-1",
					Attributes: templ.Attributes{
						"data-preset-days": preset.Days,
					},
				}) {
					{ preset.Label }
				}
			}
		}
	}
	<script>
		(() => {
			const calendar = () => document.getElementById("calendar-presets");
			document.querySelectorAll("[data-preset-days]").forEach((btn) => {
				btn.addEventListener("click", () => {
					const date = new Date();
					date.setDate(date.getDate() + parseInt(btn.dataset.presetDays, 10));
					const iso = date.toLocaleDateString("sv-SE");
					calendar().dispatchEvent(
						new CustomEvent("calendar-set", { bubbles: true, detail: { date: iso } }),
					);
				});
			});
		})();
	</script>
}
```

## Date and Time Picker

```templ
package examples

import (
	"time"

	"github.com/axadrn/shadcn-templ/v2/components/calendar"
	"github.com/axadrn/shadcn-templ/v2/components/card"
	"github.com/axadrn/shadcn-templ/v2/components/field"
	"github.com/axadrn/shadcn-templ/v2/components/icon"
	"github.com/axadrn/shadcn-templ/v2/components/inputgroup"
)

templ CalendarTime() {
	{{ selected := time.Date(time.Now().Year(), time.Now().Month(), 12, 0, 0, 0, 0, time.Local) }}
	@card.Card(card.Props{Size: card.SizeSm, Class: "mx-auto w-fit"}) {
		@card.Content() {
			@calendar.Calendar(calendar.Props{
				Selected: selected,
				Class: "p-0",
			})
		}
		@card.Footer(card.FooterProps{Class: "border-t bg-card"}) {
			@field.Group() {
				@field.Field() {
					@field.Label(field.LabelProps{For: "calendar-time-from"}) {
						Start Time
					}
					@inputgroup.InputGroup() {
						@inputgroup.Input(inputgroup.InputProps{
							ID:    "calendar-time-from",
							Type:  "time",
							Value: "10:30:00",
							Class: "appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none",
							Attributes: templ.Attributes{
								"step": "1",
							},
						})
						@inputgroup.Addon() {
							@icon.Clock2(icon.Props{Class: "text-muted-foreground"})
						}
					}
				}
				@field.Field() {
					@field.Label(field.LabelProps{For: "calendar-time-to"}) {
						End Time
					}
					@inputgroup.InputGroup() {
						@inputgroup.Input(inputgroup.InputProps{
							ID:    "calendar-time-to",
							Type:  "time",
							Value: "12:30:00",
							Class: "appearance-none [&::-webkit-calendar-picker-indicator]:hidden [&::-webkit-calendar-picker-indicator]:appearance-none",
							Attributes: templ.Attributes{
								"step": "1",
							},
						})
						@inputgroup.Addon() {
							@icon.Clock2(icon.Props{Class: "text-muted-foreground"})
						}
					}
				}
			}
		}
	}
}
```

## Booked dates

```templ
package examples

import (
	"time"

	"github.com/axadrn/shadcn-templ/v2/components/calendar"
	"github.com/axadrn/shadcn-templ/v2/components/card"
)

templ CalendarBookedDates() {
	{{
		selected := time.Date(time.Now().Year(), 1, 6, 0, 0, 0, 0, time.Local)
		booked := make([]time.Time, 15)
		for i := range booked {
			booked[i] = time.Date(time.Now().Year(), 1, 12+i, 0, 0, 0, 0, time.Local)
		}
	}}
	@card.Card(card.Props{Class: "mx-auto w-fit p-0"}) {
		@card.Content(card.ContentProps{Class: "p-0"}) {
			@calendar.Calendar(calendar.Props{
				Selected:       selected,
				BookedDates: booked,
			})
		}
	}
}
```

## Custom Cell Size

```templ
package examples

import (
	"time"

	"github.com/axadrn/shadcn-templ/v2/components/calendar"
	"github.com/axadrn/shadcn-templ/v2/components/card"
)

templ CalendarCustomCellSize() {
	{{
		from := time.Date(time.Now().Year(), 12, 8, 0, 0, 0, 0, time.Local)
		to := from.AddDate(0, 0, 10)
	}}
	@card.Card(card.Props{Class: "mx-auto w-fit p-0"}) {
		@card.Content(card.ContentProps{Class: "p-0"}) {
			@calendar.Calendar(calendar.Props{
				ID:            "calendar-custom-cell-size",
				Mode:          calendar.ModeRange,
				Selected:         from,
				EndValue:      to,
				CaptionLayout: calendar.CaptionLayoutDropdown,
				Class:         "[--cell-size:--spacing(10)] md:[--cell-size:--spacing(12)]",
			})
		}
	}
	<script>
		(() => {
			const root = () => document.getElementById("calendar-custom-cell-size");
			function decorate() {
				root().querySelectorAll("[data-tui-calendar-day]").forEach((btn) => {
					if (btn.querySelector("span") || btn.getAttribute("data-outside") === "true") return;
					const date = new Date(btn.getAttribute("data-tui-calendar-day"));
					const weekend = date.getDay() === 0 || date.getDay() === 6;
					const price = document.createElement("span");
					price.textContent = weekend ? "$120" : "$100";
					btn.appendChild(price);
				});
			}
			root().addEventListener("calendar-rendered", decorate);
			decorate();
		})();
	</script>
}
```

You can customize the size of calendar cells using the `--cell-size` CSS variable. You can also make it responsive by using breakpoint-specific values:

```templ showLineNumbers
@calendar.Calendar(calendar.Props{
	Class: "rounded-lg border [--cell-size:--spacing(11)] md:[--cell-size:--spacing(12)]",
})
```

Or use fixed values:

```templ showLineNumbers
@calendar.Calendar(calendar.Props{
	Class: "rounded-lg border [--cell-size:2.75rem] md:[--cell-size:3rem]",
})
```

## Week Numbers

Use `ShowWeekNumber` to show week numbers.

```templ
package examples

import (
	"time"

	"github.com/axadrn/shadcn-templ/v2/components/calendar"
	"github.com/axadrn/shadcn-templ/v2/components/card"
)

templ CalendarWeekNumbers() {
	{{ selected := time.Date(time.Now().Year(), 1, 12, 0, 0, 0, 0, time.Local) }}
	@card.Card(card.Props{Class: "mx-auto w-fit p-0"}) {
		@card.Content(card.ContentProps{Class: "p-0"}) {
			@calendar.Calendar(calendar.Props{
				Selected:           selected,
				ShowWeekNumber: true,
			})
		}
	}
}
```

## API Reference

### Calendar

The `Calendar` component displays a month grid for selecting a date or a range of dates.

| Prop              | Type                                                | Default               |
| ----------------- | --------------------------------------------------- | --------------------- |
| `Mode`            | `ModeSingle \| ModeRange`                          | `ModeSingle`          |
| `CaptionLayout`   | `CaptionLayoutLabel \| CaptionLayoutDropdown`      | `CaptionLayoutLabel`  |
| `Selected`           | `time.Time`                                         | -                     |
| `EndValue`        | `time.Time`                                         | -                     |
| `Month`           | `time.Time`                                         | `Selected` or now        |
| `Name`            | `string`                                            | -                     |
| `EndName`         | `string`                                            | `Name + "-end"`       |
| `Locale`       | `string` (BCP 47, e.g. "de-DE")                     | `"en-US"`             |
| `WeekStartsOn`     | `Day`                                               | `Sunday`              |
| `HideOutsideDays` | `bool`                                              | `false`               |
| `FixedWeeks`      | `bool`                                              | `false`               |
| `ShowWeekNumber` | `bool`                                              | `false`               |
| `MinDate`         | `time.Time`                                         | -                     |
| `MaxDate`         | `time.Time`                                         | -                     |
| `Disabled`   | `[]time.Time`                                       | -                     |
| `BookedDates`     | `[]time.Time`                                       | -                     |
| `NumberOfMonths`  | `int`                                               | `1`                   |
| `Class`           | `string`                                            | -                     |
