---
title: "Calendar"
description: "Displays dates and days of the week, facilitating date-related interactions."
canonical_url: "https://vinicunca.dev/akar/components/calendar"
---
# Calendar

> Displays dates and days of the week, facilitating date-related interactions.

`````vue [index.vue]
<script setup lang="ts">
import type { CalendarRootProps } from 'akar'
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNext, CalendarPrev, CalendarRoot } from 'akar'
import './styles.css'

const isDateUnavailable: CalendarRootProps['isDateUnavailable'] = (date) => {
  return date.day === 17 || date.day === 18
}
</script>

<template>
  <div class="akar-demo akar-demo-Calendar">
    <CalendarRoot
        v-slot="{ weekDays, grid }"
        :is-date-unavailable="isDateUnavailable"
        class="Calendar"
        fixed-weeks
      >
        <CalendarHeader class="CalendarHeader">
          <CalendarPrev
            class="CalendarNavButton"
          >
            <PIcon
              name="i-lucide-chevron-left"
              class="Icon"
            />
          </CalendarPrev>
          <CalendarHeading class="CalendarHeading" />
          <CalendarNext
            class="CalendarNavButton"
          >
            <PIcon
              name="i-lucide-chevron-right"
              class="Icon"
            />
          </CalendarNext>
        </CalendarHeader>
        <div
          class="CalendarWrapper"
        >
          <CalendarGrid
            v-for="month in grid"
            :key="month.value.toString()"
            class="CalendarGrid"
          >
            <CalendarGridHead>
              <CalendarGridRow class="CalendarGridRow">
                <CalendarHeadCell
                  v-for="day in weekDays"
                  :key="day"
                  class="CalendarHeadCell"
                >
                  {{ day }}
                </CalendarHeadCell>
              </CalendarGridRow>
            </CalendarGridHead>
            <CalendarGridBody class="CalendarGridWrapper">
              <CalendarGridRow
                v-for="(weekDates, index) in month.rows"
                :key="`weekDate-${index}`"
                class="CalendarGridRow"
              >
                <CalendarCell
                  v-for="weekDate in weekDates"
                  :key="weekDate.toString()"
                  :date="weekDate"
                  class="CalendarCell"
                >
                  <CalendarCellTrigger
                    :day="weekDate"
                    :month="month.value"
                    class="CalendarCellTrigger"
                  />
                </CalendarCell>
              </CalendarGridRow>
            </CalendarGridBody>
          </CalendarGrid>
        </div>
      </CalendarRoot>
  </div>
</template>
```

```css [styles.css]
@import '../_colors/black-alpha.css';
@import '../_colors/grass.css';

@scope (.akar-demo-Calendar) {
.Icon {
  width: 1.5rem;
  height: 1.5rem;
}

.Calendar {
  margin-top: 1.5rem;
  border-width: 1px;
  border-color: #000000;
  background-color: #ffffff;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  padding: 22px;
}

.CalendarHeader {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.CalendarNavButton {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  width: 2.5rem;
  height: 2.5rem;
  color: #000000;
  background-color: transparent;
  cursor: pointer;
}

.CalendarNavButton:hover {
  color: #ffffff;
  background-color: #000000;
}

.CalendarHeading {
  font-weight: 500;
  color: #000000;
}

.CalendarWrapper {
  display: flex;
  padding-top: 1rem;
  margin-top: 1rem;
  flex-direction: column;
}

@media (min-width: 640px) {
  .CalendarWrapper {
    margin-left: 1rem;
    margin-top: 0;
    flex-direction: row;
  }
}

.CalendarGrid {
  margin-top: 0.25rem;
  width: 100%;
  user-select: none;
  border-collapse: collapse;
}

.CalendarGridRow {
  display: grid;
  margin-bottom: 0.25rem;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  width: 100%;
}

.CalendarGridRow[data-reka-calendar-month-view] {
  grid-template-columns: repeat(7, minmax(0, 1fr));
}

.CalendarHeadCell {
  border-radius: 0.375rem;
  font-size: 0.75rem;
  line-height: 1rem;
  color: #000000;
  font-weight: 400;
}

.CalendarCell {
  position: relative;
  font-size: 0.875rem;
  line-height: 1.25rem;
  text-align: center;
}

.CalendarCellTrigger {
  display: flex;
  position: relative;
  padding: 0.5rem;
  justify-content: center;
  align-items: center;
  border-width: 1px;
  border-color: transparent;
  outline-style: none;
  font-size: 0.875rem;
  line-height: 1.25rem;
  font-weight: 400;
  color: #000000;
  white-space: nowrap;
  background-color: transparent;
}

.CalendarCellTrigger:hover {
  border-color: #000000;
}

.CalendarCellTrigger:focus {
  box-shadow: 0 0 0 2px #000000;
}

.CalendarCellTrigger[data-disabled] {
  cursor: none;
  color: rgba(0,0,0,0.3);
}

.CalendarCellTrigger[data-selected] {
  background-color: #000000;
  color: #ffffff;
  font-weight: 500;
}

.CalendarCellTrigger[data-selected]::before {
  background-color: #FFFFFF;
}

.CalendarCellTrigger[data-unavailable] {
  color: rgba(0,0,0,0.3);
  text-decoration: line-through;
}

.CalendarCellTrigger::before {
  content: '';
  position: absolute;
  top: 5px;
  left: 0;
  width: 0.25rem;
  height: 0.25rem;
  border-radius: 9999px;
  background-color: #FFFFFF;
}

.CalendarCellTrigger[data-today]::before {
  display: block;
  background-color: var(--grass-9);
}
}
```

## Features

- Full keyboard navigation
- Can be controlled or uncontrolled
- Focus is fully managed
- Localization support
- Highly composable

## Preface

The component depends on the [@internationalized/date](https://react-spectrum.adobe.com/internationalized/date/index.html) package, which solves a lot of the problems that come with working with dates and times in JavaScript.

We highly recommend reading through the documentation for the package to get a solid feel for how it works, and you'll need to install it in your project to use the date-related components.

## Installation

Install the date package.

```bash [pnpm]
pnpm add @internationalized/date
```

```bash [yarn]
yarn add @internationalized/date
```

```bash [npm]
npm install @internationalized/date
```

```bash [bun]
bun add @internationalized/date
```

Install the component from your command line.

```bash [pnpm]
pnpm add akar
```

```bash [yarn]
yarn add akar
```

```bash [npm]
npm install akar
```

```bash [bun]
bun add akar
```

## Anatomy

Import all parts and piece them together.

```vue
<script setup>
import {
  CalendarCell,
  CalendarCellTrigger,
  CalendarGrid,
  CalendarGridBody,
  CalendarGridHead,
  CalendarGridRow,
  CalendarHeadCell,
  CalendarHeader,
  CalendarHeading,
  CalendarNext,
  CalendarPrev,
  CalendarRoot,
} from 'akar';
</script>

<template>
  <CalendarRoot>
    <CalendarHeader>
      <CalendarPrev />
      <CalendarHeading />
      <CalendarNext />
    </CalendarHeader>
    <CalendarGrid>
      <CalendarGridHead>
        <CalendarGridRow>
          <CalendarHeadCell />
        </CalendarGridRow>
      </CalendarGridHead>
      <CalendarGridBody>
        <CalendarGridRow>
          <CalendarCell>
            <CalendarCellTrigger />
          </CalendarCell>
        </CalendarGridRow>
      </CalendarGridBody>
    </CalendarGrid>
  </CalendarRoot>
</template>
```

## API Reference

### Root

Contains all the parts of a calendar

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |
| `calendarLabel` |  | `string` | The accessible label for the calendar |
| `defaultPlaceholder` |  | `DateValue` | The default placeholder date |
| `defaultValue` |  | `DateValue` | The default value for the calendar |
| `dir` |  | `"ltr" \| "rtl"` | The reading direction of the calendar when applicable.<br><br>If omitted, inherits globally from `ConfigProvider` or assumes LTR (left-to-right) reading mode. |
| `disabled` | `false` | `boolean` | Whether the calendar is disabled |
| `disableDaysOutsideCurrentView` | `false` | `boolean` | Whether or not to disable days outside the current view. |
| `fixedWeeks` | `false` | `boolean` | Whether or not to always display 6 weeks in the calendar |
| `initialFocus` | `false` | `boolean` | If true, the calendar will focus the selected day, today, or the first day of the month depending on what is visible when the calendar is mounted |
| `isDateDisabled` |  | `Matcher` | A function that returns whether or not a date is disabled |
| `isDateUnavailable` |  | `Matcher` | A function that returns whether or not a date is unavailable |
| `locale` |  | `string` | The locale to use for formatting dates |
| `maxValue` |  | `DateValue` | The maximum date that can be selected |
| `minValue` |  | `DateValue` | The minimum date that can be selected |
| `modelValue` |  | `DateValue \| DateValue[] \| null` | The controlled selected date value of the calendar. Can be bound as `v-model`. |
| `multiple` | `false` | `boolean` | Whether multiple dates can be selected |
| `nextPage` |  | `((placeholder: DateValue) => DateValue)` | A function that returns the next page of the calendar. It receives the current placeholder as an argument inside the component. |
| `numberOfMonths` | `1` | `number` | The number of months to display at once |
| `pagedNavigation` | `false` | `boolean` | This property causes the previous and next buttons to navigate by the number of months displayed at once, rather than one month |
| `placeholder` |  | `DateValue` | The placeholder date, which is used to determine what month to display when no date is selected |
| `preventDeselect` | `false` | `boolean` | Whether or not to prevent the user from deselecting a date without selecting another date first |
| `prevPage` |  | `((placeholder: DateValue) => DateValue)` | A function that returns the previous page of the calendar. It receives the current placeholder as an argument inside the component. |
| `readonly` | `false` | `boolean` | Whether the calendar is readonly |
| `weekdayFormat` | `"narrow"` | `"narrow" \| "short" \| "long"` | The format to use for the weekday strings provided via the weekdays slot prop |
| `weekStartsOn` |  | `0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6` | The day of the week to start the calendar on |

**Events**

| Event | Payload | Description |
| --- | --- | --- |
| `update:modelValue` | `date: DateValue` | Event handler called whenever the model value changes |
| `update:placeholder` | `date: DateValue` | Event handler called whenever the placeholder value changes |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `date` | `DateValue` | The current date of the placeholder |
| `grid` | `Grid<DateValue>[]` | The grid of dates |
| `weekDays` | `string[]` | The days of the week |
| `weekStartsOn` | `0 \| 1 \| 2 \| 3 \| 4 \| 5 \| 6` | The start of the week |
| `locale` | `string` | The calendar locale |
| `fixedWeeks` | `boolean` | Whether or not to always display 6 weeks in the calendar |
| `modelValue` | `DateValue \| DateValue[]` | The current date of the calendar |

[CalendarRoot.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Calendar/CalendarRoot.vue)

| Data attribute | Value |
| --- | --- |
| `[data-readonly]` | Present when readonly |
| `[data-disabled]` | Present when disabled |
| `[data-invalid]` | Present when invalid |

### Header

Contains the navigation buttons and the heading segments.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |

[CalendarHeader.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Calendar/CalendarHeader.vue)

### Prev Button

Calendar navigation button. It navigates the calendar one month/year/decade in the past based on the current calendar view.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"button"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |
| `prevPage` |  | `((placeholder: DateValue) => DateValue)` | The function to be used for the prev page. Overwrites the `prevPage` function set on the `CalendarRoot`. |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `disabled` | `boolean` | Current disable state |

[CalendarPrev.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Calendar/CalendarPrev.vue)

| Data attribute | Value |
| --- | --- |
| `[data-disabled]` | Present when disabled |

### Next Button

Calendar navigation button. It navigates the calendar one month/year/decade in the future based on the current calendar view.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"button"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |
| `nextPage` |  | `((placeholder: DateValue) => DateValue)` | The function to be used for the next page. Overwrites the `nextPage` function set on the `CalendarRoot`. |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `disabled` | `boolean` | Current disable state |

[CalendarNext.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Calendar/CalendarNext.vue)

| Data attribute | Value |
| --- | --- |
| `[data-disabled]` | Present when disabled |

### Heading

Heading for displaying the current month and year

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `headingValue` | `string` | Current month and year |

[CalendarHeading.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Calendar/CalendarHeading.vue)

| Data attribute | Value |
| --- | --- |
| `[data-disabled]` | Present when disabled |

### Grid

Container for wrapping the calendar grid.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"table"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |

[CalendarGrid.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Calendar/CalendarGrid.vue)

| Data attribute | Value |
| --- | --- |
| `[data-readonly]` | Present when readonly |
| `[data-disabled]` | Present when disabled |

### Grid Head

Container for wrapping the grid head.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"thead"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |

[CalendarGridHead.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Calendar/CalendarGridHead.vue)

### Grid Body

Container for wrapping the grid body.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"tbody"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |

[CalendarGridBody.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Calendar/CalendarGridBody.vue)

### Grid Row

Container for wrapping the grid row.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"tr"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |

[CalendarGridRow.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Calendar/CalendarGridRow.vue)

### Head Cell

Container for wrapping the head cell. Used for displaying the week days.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"th"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |

[CalendarHeadCell.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Calendar/CalendarHeadCell.vue)

### Cell

Container for wrapping the calendar cells.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"td"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |
| `date*` |  | `DateValue` | The date value for the cell |

[CalendarCell.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Calendar/CalendarCell.vue)

| Data attribute | Value |
| --- | --- |
| `[data-disabled]` | Present when disabled |

### Cell Trigger

Interactable container for displaying the cell dates. Clicking it selects the date.

**Props**

| Prop | Default | Type | Description |
| --- | --- | --- | --- |
| `as` | `"div"` | `AsTag \| Component` | The element or component this component should render as. Can be overwritten by `asChild`. |
| `asChild` |  | `boolean` | Change the default rendered element for the one passed as a child, merging their props and behavior.<br><br>Read our [Composition](/akar/guides/composition) guide for more details. |
| `day*` |  | `DateValue` | The date value provided to the cell trigger |
| `month*` |  | `DateValue` | The month in which the cell is rendered |

**Slots**

| Slot | Payload | Description |
| --- | --- | --- |
| `dayValue` | `string` | Current day |
| `disabled` | `boolean` | Current disable state |
| `selected` | `boolean` | Current selected state |
| `today` | `boolean` | Current today state |
| `outsideView` | `boolean` | Current outside view state |
| `outsideVisibleView` | `boolean` | Current outside visible view state |
| `unavailable` | `boolean` | Current unavailable state |

[CalendarCellTrigger.vue source](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Calendar/CalendarCellTrigger.vue)

| Data attribute | Value |
| --- | --- |
| `[data-selected]` | Present when selected |
| `[data-value]` | The ISO string value of the date. |
| `[data-disabled]` | Present when disabled |
| `[data-unavailable]` | Present when unavailable |
| `[data-today]` | Present when today |
| `[data-outside-view]` | Present when the date is outside the current month it is displayed in. |
| `[data-outside-visible-view]` | Present when the date is outside the months that are visible on the calendar. |
| `[data-focused]` | Present when focused |

## Examples

### Calendar with Year Incrementation

This example showcases a calendar which allows incrementing the year.

```vue [index.vue]
<script setup lang="ts">
import type { DateValue } from '@internationalized/date'
import type { CalendarRootProps } from 'akar'
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNext, CalendarPrev, CalendarRoot } from 'akar'
import './styles.css'

const isDateUnavailable: CalendarRootProps['isDateUnavailable'] = (date) => {
  return date.day === 17 || date.day === 18
}

function pagingFunc(date: DateValue, sign: -1 | 1) {
  if (sign === -1)
    return date.subtract({ years: 1 })
  return date.add({ years: 1 })
}
</script>

<template>
  <div class="akar-demo akar-demo-CalendarYearIncrement">
    <CalendarRoot
        v-slot="{ weekDays, grid }"
        :is-date-unavailable="isDateUnavailable"
        class="Calendar"
        fixed-weeks
      >
        <CalendarHeader class="CalendarHeader">
          <CalendarPrev
            class="CalendarNavButton"
            :prev-page="(date: DateValue) => pagingFunc(date, -1)"
          >
            <PIcon
              name="i-lucide-chevrons-left"
              class="Icon"
            />
          </CalendarPrev>
          <CalendarPrev
            class="CalendarNavButton"
          >
            <PIcon
              name="i-lucide-chevron-left"
              class="Icon"
            />
          </CalendarPrev>
          <CalendarHeading class="CalendarHeading" />
          <CalendarNext
            class="CalendarNavButton"
          >
            <PIcon
              name="i-lucide-chevron-right"
              class="Icon"
            />
          </CalendarNext>

          <CalendarNext
            class="CalendarNavButton"
            :next-page="(date: DateValue) => pagingFunc(date, 1)"
          >
            <PIcon
              name="i-lucide-chevrons-right"
              class="Icon"
            />
          </CalendarNext>
        </CalendarHeader>
        <div
          class="CalendarWrapper"
        >
          <CalendarGrid
            v-for="month in grid"
            :key="month.value.toString()"
            class="CalendarGrid"
          >
            <CalendarGridHead>
              <CalendarGridRow class="CalendarGridRow">
                <CalendarHeadCell
                  v-for="day in weekDays"
                  :key="day"
                  class="CalendarHeadCell"
                >
                  {{ day }}
                </CalendarHeadCell>
              </CalendarGridRow>
            </CalendarGridHead>
            <CalendarGridBody class="CalendarGridWrapper">
              <CalendarGridRow
                v-for="(weekDates, index) in month.rows"
                :key="`weekDate-${index}`"
                class="CalendarGridRow"
              >
                <CalendarCell
                  v-for="weekDate in weekDates"
                  :key="weekDate.toString()"
                  :date="weekDate"
                  class="CalendarCell"
                >
                  <CalendarCellTrigger
                    :day="weekDate"
                    :month="month.value"
                    class="CalendarCellTrigger"
                  />
                </CalendarCell>
              </CalendarGridRow>
            </CalendarGridBody>
          </CalendarGrid>
        </div>
      </CalendarRoot>
  </div>
</template>
```

```css [styles.css]
@import '../_colors/black-alpha.css';
@import '../_colors/grass.css';

@scope (.akar-demo-CalendarYearIncrement) {
.Icon {
  width: 1.5rem;
  height: 1.5rem;
}

.Calendar {
  margin-top: 1.5rem;
  border-width: 1px;
  border-color: #000000;
  background-color: #ffffff;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  padding: 22px;
}

.CalendarHeader {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.CalendarNavButton {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  width: 2.5rem;
  height: 2.5rem;
  color: #000000;
  background-color: transparent;
  cursor: pointer;
}

.CalendarNavButton:hover {
  color: #ffffff;
  background-color: #000000;
}

.CalendarHeading {
  font-weight: 500;
  color: #000000;
  color: 15px;
}

.CalendarWrapper {
  display: flex;
  padding-top: 1rem;
  margin-top: 1rem;
  flex-direction: column;
}

@media (min-width: 640px) {
  .CalendarWrapper {
    margin-left: 1rem;
    margin-top: 0;
    flex-direction: row;
  }
}

.CalendarGrid {
  margin-top: 0.25rem;
  width: 100%;
  user-select: none;
  border-collapse: collapse;
}

.CalendarGridRow {
  display: grid;
  margin-bottom: 0.25rem;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  width: 100%;
}

.CalendarGridRow[data-reka-calendar-month-view] {
  grid-template-columns: repeat(7, minmax(0, 1fr));
}

.CalendarHeadCell {
  border-radius: 0.375rem;
  font-size: 0.75rem;
  line-height: 1rem;
  color: #000000;
  font-weight: 400;
}

.CalendarCell {
  position: relative;
  font-size: 0.875rem;
  line-height: 1.25rem;
  text-align: center;
}

.CalendarCellTrigger {
  display: flex;
  position: relative;
  padding: 0.5rem;
  justify-content: center;
  align-items: center;
  border-width: 1px;
  border-color: transparent;
  outline-style: none;
  font-size: 0.875rem;
  line-height: 1.25rem;
  font-weight: 400;
  color: #000000;
  white-space: nowrap;
  background-color: transparent;
}

.CalendarCellTrigger:hover {
  border-color: #000000;
}

.CalendarCellTrigger:focus {
  box-shadow: 0 0 0 2px #000000;
}

.CalendarCellTrigger[data-disabled] {
  cursor: none;
  color: rgba(0,0,0,0.3);
}

.CalendarCellTrigger[data-selected] {
  background-color: #000000;
  color: #ffffff;
  font-weight: 500;
}

.CalendarCellTrigger[data-selected]::before {
  background-color: #FFFFFF;
}

.CalendarCellTrigger[data-unavailable] {
  color: rgba(0,0,0,0.3);
  text-decoration: line-through;
}

.CalendarCellTrigger::before {
  content: '';
  position: absolute;
  top: 5px;
  left: 0;
  width: 0.25rem;
  height: 0.25rem;
  border-radius: 9999px;
  background-color: #FFFFFF;
}

.CalendarCellTrigger[data-today]::before {
  display: block;
  background-color: var(--grass-9);
}

/* reset */
button {
  all: unset;
}

.Wrapper {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.Label {
  color: #fff;
}

.SelectTrigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  padding: 0 15px;
  font-size: 13px;
  line-height: 1;
  height: 35px;
  gap: 5px;
  background-color: white;
  color: var(--grass-11);
  box-shadow: 0 2px 10px var(--black-a7);
}
.SelectTrigger:hover {
  background-color: var(--mauve-3);
}
.SelectTrigger:focus {
  box-shadow: 0 0 0 2px black;
}
.SelectTrigger[data-placeholder] {
  color: var(--grass-9);
}

.SelectIcon {
  color: Var(--grass-11);
}

.SelectContent {
  overflow: hidden;
  background-color: white;
  border-radius: 6px;
  box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35), 0px 10px 20px -15px rgba(22, 23, 24, 0.2);
}

.SelectViewport {
  padding: 5px;
}

.SelectItem {
  font-size: 13px;
  line-height: 1;
  color: var(--grass-11);
  border-radius: 3px;
  display: flex;
  align-items: center;
  height: 25px;
  padding: 0 35px 0 25px;
  position: relative;
  user-select: none;
}
.SelectItem[data-disabled] {
  color: var(--mauve-8);
  pointer-events: none;
}
.SelectItem[data-highlighted] {
  outline: none;
  background-color: var(--grass-9);
  color: var(--grass-1);
}

.SelectLabel {
  padding: 0 25px;
  font-size: 12px;
  line-height: 25px;
  color: var(--mauve-11);
}

.SelectSeparator {
  height: 1px;
  background-color: var(--grass-6);
  margin: 5px;
}

.SelectItemIndicator {
  position: absolute;
  left: 0;
  width: 25px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.SelectScrollButton {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 25px;
  background-color: white;
  color: var(--grass-11);
  cursor: default;
}
}
```

### Calendar with Locale and Calendar System Selection

This example showcases some of the available locales and how the calendar systems are displayed.

```vue [index.vue]
<script setup lang="ts">
import { createCalendar, getLocalTimeZone, toCalendar, today } from '@internationalized/date'
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNext, CalendarPrev, CalendarRoot, Label, SelectContent, SelectGroup, SelectItem, SelectItemIndicator, SelectItemText, SelectLabel, SelectPortal, SelectRoot, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, SelectViewport } from 'akar'
import { computed, ref } from 'vue'

const preferences = [
  { locale: 'en-US', label: 'Default', ordering: 'gregory' },
  { label: 'Arabic (Algeria)', locale: 'ar-DZ', territories: 'DJ DZ EH ER IQ JO KM LB LY MA MR OM PS SD SY TD TN YE', ordering: 'gregory islamic islamic-civil islamic-tbla' },
  { label: 'Arabic (United Arab Emirates)', locale: 'ar-AE', territories: 'AE BH KW QA', ordering: 'gregory islamic-umalqura islamic islamic-civil islamic-tbla' },
  { label: 'Arabic (Egypt)', locale: 'ar-EG', territories: 'EG', ordering: 'gregory coptic islamic islamic-civil islamic-tbla' },
  { label: 'Arabic (Saudi Arabia)', locale: 'ar-SA', territories: 'SA', ordering: 'islamic-umalqura gregory islamic islamic-rgsa' },
  { label: 'Farsi (Iran)', locale: 'fa-IR', territories: 'IR', ordering: 'persian gregory islamic islamic-civil islamic-tbla' },
  { label: 'Farsi (Afghanistan)', locale: 'fa-AF', territories: 'AF IR', ordering: 'persian gregory islamic islamic-civil islamic-tbla' },
  { label: 'Amharic (Ethiopia)', locale: 'am-ET', territories: 'ET', ordering: 'gregory ethiopic ethioaa' },
  { label: 'Hebrew (Israel)', locale: 'he-IL', territories: 'IL', ordering: 'gregory hebrew islamic islamic-civil islamic-tbla' },
  { label: 'Hindi (India)', locale: 'hi-IN', territories: 'IN', ordering: 'gregory indian' },
  { label: 'Japanese (Japan)', locale: 'ja-JP', territories: 'JP', ordering: 'gregory japanese' },
  { label: 'Thai (Thailand)', locale: 'th-TH', territories: 'TH', ordering: 'buddhist gregory' },
  { label: 'Chinese (Taiwan)', locale: 'zh-TW', territories: 'TW', ordering: 'gregory roc chinese' },
]

const calendars = [
  { key: 'gregory', name: 'Gregorian' },
  { key: 'japanese', name: 'Japanese' },
  { key: 'buddhist', name: 'Buddhist' },
  { key: 'roc', name: 'Taiwan' },
  { key: 'persian', name: 'Persian' },
  { key: 'indian', name: 'Indian' },
  { key: 'islamic-umalqura', name: 'Islamic (Umm al-Qura)' },
  { key: 'islamic-civil', name: 'Islamic Civil' },
  { key: 'islamic-tbla', name: 'Islamic Tabular' },
  { key: 'hebrew', name: 'Hebrew' },
  { key: 'coptic', name: 'Coptic' },
  { key: 'ethiopic', name: 'Ethiopic' },
  { key: 'ethioaa', name: 'Ethiopic (Amete Alem)' },
]

const locale = ref(preferences[0].locale)
const calendar = ref(calendars[0].key)

const pref = computed(() => preferences.find(p => p.locale === locale.value))
const preferredCalendars = computed(() => pref.value ? pref.value.ordering.split(' ').map(p => calendars.find(c => c.key === p)).filter(Boolean) : [calendars[0]])
const otherCalendars = computed(() => calendars.filter(c => !preferredCalendars.value.some(p => p!.key === c.key)))

function updateLocale(newLocale: string) {
  locale.value = newLocale
  calendar.value = pref.value!.ordering.split(' ')[0]
}
const value = computed(() => toCalendar(today(getLocalTimeZone()), createCalendar(calendar.value)))
</script>

<template>
  <div class="akar-demo akar-demo-CalendarSelect">
    <div class="Wrapper">
        <Label class="Label">Locale</Label>
        <SelectRoot
          v-model="locale"
          @update:model-value="updateLocale"
        >
          <SelectTrigger
            class="SelectTrigger"
            aria-label="Select a locale"
          >
            <SelectValue placeholder="Please select a locale">
              {{ pref!.label }}
            </SelectValue>
            <PIcon
              name="i-lucide-chevron-down"
              class="Icon"
            />
          </SelectTrigger>

          <SelectPortal>
            <SelectContent
              class="SelectContent"
              :side-offset="5"
            >
              <SelectScrollUpButton class="SelectScrollButton">
                <PIcon name="i-lucide-chevron-up" />
              </SelectScrollUpButton>

              <SelectViewport class="SelectViewport">
                <SelectItem
                  v-for="(option, index) in preferences"
                  :key="index"
                  class="SelectItem"
                  :value="option.locale"
                >
                  <SelectItemIndicator class="SelectItemIndicator">
                    <PIcon name="i-lucide-check" />
                  </SelectItemIndicator>
                  <SelectItemText>
                    {{ option.label }}
                  </SelectItemText>
                </SelectItem>
              </SelectViewport>

              <SelectScrollDownButton class="SelectScrollButton">
                <PIcon name="i-lucide-chevron-down" />
              </SelectScrollDownButton>
            </SelectContent>
          </SelectPortal>
        </SelectRoot>
        <Label class="Label">Calendar</Label>
        <SelectRoot v-model="calendar">
          <SelectTrigger
            class="SelectTrigger"
            aria-label="Select a calendar"
          >
            <SelectValue placeholder="Please select a calendar">
              {{ calendars.find(c => c.key === calendar)?.name }}
            </SelectValue>

            <PIcon
              name="i-lucide-chevron-down"
              class="Icon"
            />
          </SelectTrigger>

          <SelectPortal>
            <SelectContent
              class="SelectContent"
              :side-offset="5"
            >
              <SelectScrollUpButton class="SelectScrollButton">
                <PIcon name="i-lucide-chevron-up" />
              </SelectScrollUpButton>

              <SelectViewport class="SelectViewport">
                <SelectLabel class="SelectLabel">
                  Preferred
                </SelectLabel>
                <SelectGroup>
                  <SelectItem
                    v-for="(option, index) in preferredCalendars"
                    :key="index"
                    class="SelectItem"
                    :value="option!.key"
                  >
                    <SelectItemIndicator class="SelectItemIndicator">
                      <PIcon name="i-lucide-check" />
                    </SelectItemIndicator>
                    <SelectItemText>
                      {{ option!.name }}
                    </SelectItemText>
                  </SelectItem>
                </SelectGroup>
                <SelectSeparator class="SelectSeparator" />
                <SelectLabel class="SelectLabel">
                  Other
                </SelectLabel>
                <SelectGroup>
                  <SelectItem
                    v-for="(option, index) in otherCalendars"
                    :key="index"
                    class="SelectItem"
                    :value="option.key"
                  >
                    <SelectItemIndicator class="SelectItemIndicator">
                      <PIcon name="i-lucide-check" />
                    </SelectItemIndicator>
                    <SelectItemText>
                      {{ option.name }}
                    </SelectItemText>
                  </SelectItem>
                </SelectGroup>
              </SelectViewport>

              <SelectScrollDownButton class="SelectScrollButton">
                <PIcon name="i-lucide-chevron-down" />
              </SelectScrollDownButton>
            </SelectContent>
          </SelectPortal>
        </SelectRoot>
        <CalendarRoot
          v-slot="{ weekDays, grid }"
          :model-value="value"
          :locale="locale"
          class="Calendar"
          fixed-weeks
        >
          <CalendarHeader class="CalendarHeader">
            <CalendarPrev
              class="CalendarNavButton"
            >
              <PIcon
                name="i-lucide-chevron-left"
                class="Icon"
              />
            </CalendarPrev>
            <CalendarHeading class="CalendarHeading" />
            <CalendarNext
              class="CalendarNavButton"
            >
              <PIcon
                name="i-lucide-chevron-right"
                class="Icon"
              />
            </CalendarNext>
          </CalendarHeader>
          <div
            class="CalendarWrapper"
          >
            <CalendarGrid
              v-for="month in grid"
              :key="month.value.toString()"
              class="CalendarGrid"
            >
              <CalendarGridHead>
                <CalendarGridRow class="CalendarGridRow">
                  <CalendarHeadCell
                    v-for="day in weekDays"
                    :key="day"
                    class="CalendarHeadCell"
                  >
                    {{ day }}
                  </CalendarHeadCell>
                </CalendarGridRow>
              </CalendarGridHead>
              <CalendarGridBody class="CalendarGridWrapper">
                <CalendarGridRow
                  v-for="(weekDates, index) in month.rows"
                  :key="`weekDate-${index}`"
                  class="CalendarGridRow"
                >
                  <CalendarCell
                    v-for="weekDate in weekDates"
                    :key="weekDate.toString()"
                    :date="weekDate"
                    class="CalendarCell"
                  >
                    <CalendarCellTrigger
                      :day="weekDate"
                      :month="month.value"
                      class="CalendarCellTrigger"
                    />
                  </CalendarCell>
                </CalendarGridRow>
              </CalendarGridBody>
            </CalendarGrid>
          </div>
        </CalendarRoot>
      </div>
  </div>
</template>
```

```css [styles.css]
@import '../_colors/black-alpha.css';
@import '../_colors/grass.css';

@scope (.akar-demo-CalendarSelect) {
.Icon {
  width: 1.5rem;
  height: 1.5rem;
}

.Calendar {
  margin-top: 1.5rem;
  border-width: 1px;
  border-color: #000000;
  background-color: #ffffff;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  padding: 22px;
}

.CalendarHeader {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.CalendarNavButton {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  width: 2.5rem;
  height: 2.5rem;
  color: #000000;
  background-color: transparent;
  cursor: pointer;
}

.CalendarNavButton:hover {
  color: #ffffff;
  background-color: #000000;
}

.CalendarHeading {
  font-weight: 500;
  color: #000000;
  color: 15px;
}

.CalendarWrapper {
  display: flex;
  padding-top: 1rem;
  margin-top: 1rem;
  flex-direction: column;
}

@media (min-width: 640px) {
  .CalendarWrapper {
    margin-left: 1rem;
    margin-top: 0;
    flex-direction: row;
  }
}

.CalendarGrid {
  margin-top: 0.25rem;
  width: 100%;
  user-select: none;
  border-collapse: collapse;
}

.CalendarGridRow {
  display: grid;
  margin-bottom: 0.25rem;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  width: 100%;
}

.CalendarGridRow[data-reka-calendar-month-view] {
  grid-template-columns: repeat(7, minmax(0, 1fr));
}

.CalendarHeadCell {
  border-radius: 0.375rem;
  font-size: 0.75rem;
  line-height: 1rem;
  color: #000000;
  font-weight: 400;
}

.CalendarCell {
  position: relative;
  font-size: 0.875rem;
  line-height: 1.25rem;
  text-align: center;
}

.CalendarCellTrigger {
  display: flex;
  position: relative;
  padding: 0.5rem;
  justify-content: center;
  align-items: center;
  border-width: 1px;
  border-color: transparent;
  outline-style: none;
  font-size: 0.875rem;
  line-height: 1.25rem;
  font-weight: 400;
  color: #000000;
  white-space: nowrap;
  background-color: transparent;
}

.CalendarCellTrigger:hover {
  border-color: #000000;
}

.CalendarCellTrigger:focus {
  box-shadow: 0 0 0 2px #000000;
}

.CalendarCellTrigger[data-disabled] {
  cursor: none;
  color: rgba(0,0,0,0.3);
}

.CalendarCellTrigger[data-selected] {
  background-color: #000000;
  color: #ffffff;
  font-weight: 500;
}

.CalendarCellTrigger[data-selected]::before {
  background-color: #FFFFFF;
}

.CalendarCellTrigger[data-unavailable] {
  color: rgba(0,0,0,0.3);
  text-decoration: line-through;
}

.CalendarCellTrigger::before {
  content: '';
  position: absolute;
  top: 5px;
  left: 0;
  width: 0.25rem;
  height: 0.25rem;
  border-radius: 9999px;
  background-color: #FFFFFF;
}

.CalendarCellTrigger[data-today]::before {
  display: block;
  background-color: var(--grass-9);
}

/* reset */
button {
  all: unset;
}

.Wrapper {
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.Label {
  color: #fff;
}

.SelectTrigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 4px;
  padding: 0 15px;
  font-size: 13px;
  line-height: 1;
  height: 35px;
  gap: 5px;
  background-color: white;
  color: var(--grass-11);
  box-shadow: 0 2px 10px var(--black-a7);
}
.SelectTrigger:hover {
  background-color: var(--mauve-3);
}
.SelectTrigger:focus {
  box-shadow: 0 0 0 2px black;
}
.SelectTrigger[data-placeholder] {
  color: var(--grass-9);
}

.SelectIcon {
  color: Var(--grass-11);
}

.SelectContent {
  overflow: hidden;
  background-color: white;
  border-radius: 6px;
  box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35), 0px 10px 20px -15px rgba(22, 23, 24, 0.2);
}

.SelectViewport {
  padding: 5px;
}

.SelectItem {
  font-size: 13px;
  line-height: 1;
  color: var(--grass-11);
  border-radius: 3px;
  display: flex;
  align-items: center;
  height: 25px;
  padding: 0 35px 0 25px;
  position: relative;
  user-select: none;
}
.SelectItem[data-disabled] {
  color: var(--mauve-8);
  pointer-events: none;
}
.SelectItem[data-highlighted] {
  outline: none;
  background-color: var(--grass-9);
  color: var(--grass-1);
}

.SelectLabel {
  padding: 0 25px;
  font-size: 12px;
  line-height: 25px;
  color: var(--mauve-11);
}

.SelectSeparator {
  height: 1px;
  background-color: var(--grass-6);
  margin: 5px;
}

.SelectItemIndicator {
  position: absolute;
  left: 0;
  width: 25px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.SelectScrollButton {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 25px;
  background-color: white;
  color: var(--grass-11);
  cursor: default;
}
}
```

### Calendar swipe gesture navigation

This component demonstrates intuitive calendar navigation using touch-based swipe gestures, user-friendly way to browse through months.

```vue [index.vue]
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
import { usePointerSwipe } from '@vueuse/core'
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNext, CalendarPrev, CalendarRoot } from 'akar'
import { onMounted, ref, useTemplateRef } from 'vue'
import './styles.css'

const calendarRef = useTemplateRef('calendarRef')
const date = ref(new CalendarDate(2023, 1, 1))

function nextPage() {
  date.value = date.value.add({ months: 1 }).copy()
}

function prevPage() {
  date.value = date.value.subtract({ months: 1 }).copy()
}

onMounted(() => {
  if (calendarRef.value) {
    usePointerSwipe(calendarRef.value.$el, {
      onSwipeEnd(_e, direction) {
        if (direction === 'none') {
          // eslint-disable-next-line no-useless-return
          return
        }
        else if (['down', 'right'].includes(direction)) {
          prevPage()
        }
        else {
          nextPage()
        }
      },
    })
  }
})
</script>

<template>
  <div class="akar-demo akar-demo-CalendarSwipe">
    <CalendarRoot
        ref="calendarRef"
        v-slot="{ weekDays, grid }"
        v-model:placeholder="date"
        class="Calendar"
        fixed-weeks
      >
        <CalendarHeader class="CalendarHeader">
          <CalendarPrev
            class="CalendarNavButton"
          >
            <PIcon
              name="i-lucide-chevron-left"
              class="Icon"
            />
          </CalendarPrev>
          <CalendarHeading class="CalendarHeading" />
          <CalendarNext
            class="CalendarNavButton"
          >
            <PIcon
              name="i-lucide-chevron-right"
              class="Icon"
            />
          </CalendarNext>
        </CalendarHeader>
        <div
          class="CalendarWrapper"
        >
          <CalendarGrid
            v-for="month in grid"
            :key="month.value.toString()"
            class="CalendarGrid"
          >
            <CalendarGridHead>
              <CalendarGridRow class="CalendarGridRow">
                <CalendarHeadCell
                  v-for="day in weekDays"
                  :key="day"
                  class="CalendarHeadCell"
                >
                  {{ day }}
                </CalendarHeadCell>
              </CalendarGridRow>
            </CalendarGridHead>
            <CalendarGridBody class="CalendarGridWrapper">
              <CalendarGridRow
                v-for="(weekDates, index) in month.rows"
                :key="`weekDate-${index}`"
                class="CalendarGridRow"
              >
                <CalendarCell
                  v-for="weekDate in weekDates"
                  :key="weekDate.toString()"
                  :date="weekDate"
                  class="CalendarCell"
                >
                  <CalendarCellTrigger
                    :day="weekDate"
                    :month="month.value"
                    class="CalendarCellTrigger"
                  />
                </CalendarCell>
              </CalendarGridRow>
            </CalendarGridBody>
          </CalendarGrid>
        </div>
      </CalendarRoot>
  </div>
</template>
```

```css [styles.css]
@import '../_colors/black-alpha.css';
@import '../_colors/grass.css';

@scope (.akar-demo-CalendarSwipe) {
.Icon {
  width: 1.5rem;
  height: 1.5rem;
}

.Calendar {
  margin-top: 1.5rem;
  border-width: 1px;
  border-color: #000000;
  background-color: #ffffff;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  padding: 22px;
}

.CalendarHeader {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.CalendarNavButton {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  width: 2.5rem;
  height: 2.5rem;
  color: #000000;
  background-color: transparent;
  cursor: pointer;
}

.CalendarNavButton:hover {
  color: #ffffff;
  background-color: #000000;
}

.CalendarHeading {
  font-weight: 500;
  color: #000000;
}

.CalendarWrapper {
  display: flex;
  padding-top: 1rem;
  margin-top: 1rem;
  flex-direction: column;
}

@media (min-width: 640px) {
  .CalendarWrapper {
    margin-left: 1rem;
    margin-top: 0;
    flex-direction: row;
  }
}

.CalendarGrid {
  margin-top: 0.25rem;
  width: 100%;
  user-select: none;
  border-collapse: collapse;
}

.CalendarGridRow {
  display: grid;
  margin-bottom: 0.25rem;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  width: 100%;
}

.CalendarGridRow[data-reka-calendar-month-view] {
  grid-template-columns: repeat(7, minmax(0, 1fr));
}

.CalendarHeadCell {
  border-radius: 0.375rem;
  font-size: 0.75rem;
  line-height: 1rem;
  color: #000000;
  font-weight: 400;
}

.CalendarCell {
  position: relative;
  font-size: 0.875rem;
  line-height: 1.25rem;
  text-align: center;
}

.CalendarCellTrigger {
  display: flex;
  position: relative;
  padding: 0.5rem;
  justify-content: center;
  align-items: center;
  border-width: 1px;
  border-color: transparent;
  outline-style: none;
  font-size: 0.875rem;
  line-height: 1.25rem;
  font-weight: 400;
  color: #000000;
  white-space: nowrap;
  background-color: transparent;
}

.CalendarCellTrigger:hover {
  border-color: #000000;
}

.CalendarCellTrigger:focus {
  box-shadow: 0 0 0 2px #000000;
}

.CalendarCellTrigger[data-disabled] {
  cursor: none;
  color: rgba(0,0,0,0.3);
}

.CalendarCellTrigger[data-selected] {
  background-color: #000000;
  color: #ffffff;
  font-weight: 500;
}

.CalendarCellTrigger[data-selected]::before {
  background-color: #FFFFFF;
}

.CalendarCellTrigger[data-unavailable] {
  color: rgba(0,0,0,0.3);
  text-decoration: line-through;
}

.CalendarCellTrigger::before {
  content: '';
  position: absolute;
  top: 5px;
  left: 0;
  width: 0.25rem;
  height: 0.25rem;
  border-radius: 9999px;
  background-color: #FFFFFF;
}

.CalendarCellTrigger[data-today]::before {
  display: block;
  background-color: var(--grass-9);
}
}
```

### Calendar week numbers

This example showcases usage of the CalendarWeek component used to display the number of the week.

```vue [index.vue]
<script setup lang="ts">
import { CalendarCell, CalendarCellTrigger, CalendarGrid, CalendarGridBody, CalendarGridHead, CalendarGridRow, CalendarHeadCell, CalendarHeader, CalendarHeading, CalendarNext, CalendarPrev, CalendarRoot } from 'akar'
import { getWeekNumber } from 'akar/date'
</script>

<template>
  <div class="akar-demo akar-demo-CalendarWeeks">
    <CalendarRoot
        v-slot="{ weekDays, grid }"
        class="Calendar"
        fixed-weeks
      >
        <CalendarHeader class="CalendarHeader">
          <CalendarPrev
            class="CalendarNavButton"
          >
            <PIcon
              name="i-lucide-chevron-left"
              class="Icon"
            />
          </CalendarPrev>
          <CalendarHeading class="CalendarHeading" />
          <CalendarNext
            class="CalendarNavButton"
          >
            <PIcon
              name="i-lucide-chevron-right"
              class="Icon"
            />
          </CalendarNext>
        </CalendarHeader>
        <div
          class="CalendarWrapper"
        >
          <CalendarGrid
            v-for="month in grid"
            :key="month.value.toString()"
            class="CalendarGrid"
          >
            <CalendarGridHead>
              <CalendarGridRow class="CalendarGridRow">
                <CalendarHeadCell
                  class="CalendarHeadCell"
                >
                  Wk
                </CalendarHeadCell>
                <CalendarHeadCell
                  v-for="day in weekDays"
                  :key="day"
                  class="CalendarHeadCell"
                >
                  {{ day }}
                </CalendarHeadCell>
              </CalendarGridRow>
            </CalendarGridHead>
            <CalendarGridBody class="CalendarGridWrapper">
              <CalendarGridRow
                v-for="(weekDates, index) in month.rows"
                :key="`weekDate-${index}`"
                class="CalendarGridRow"
              >
                <div
                  class="CalendarWeek"
                  :row-index="index"
                >
                  {{ getWeekNumber(weekDates[0]) }}
                </div>
                <CalendarCell
                  v-for="weekDate in weekDates"
                  :key="weekDate.toString()"
                  :date="weekDate"
                  class="CalendarCell"
                >
                  <CalendarCellTrigger
                    :day="weekDate"
                    :month="month.value"
                    class="CalendarCellTrigger"
                  />
                </CalendarCell>
              </CalendarGridRow>
            </CalendarGridBody>
          </CalendarGrid>
        </div>
      </CalendarRoot>
  </div>
</template>
```

```css [styles.css]
@import '../_colors/black-alpha.css';
@import '../_colors/grass.css';

@scope (.akar-demo-CalendarWeeks) {
.Icon {
  width: 1.5rem;
  height: 1.5rem;
}

.Calendar {
  margin-top: 1.5rem;
  border-width: 1px;
  border-color: #000000;
  background-color: #ffffff;
  box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  padding: 22px;
}

.CalendarHeader {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.CalendarNavButton {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  width: 2.5rem;
  height: 2.5rem;
  color: #000000;
  background-color: transparent;
  cursor: pointer;
}

.CalendarNavButton:hover {
  color: #ffffff;
  background-color: #000000;
}

.CalendarHeading {
  font-weight: 500;
  color: #000000;
  color: 15px;
}

.CalendarWrapper {
  display: flex;
  padding-top: 1rem;
  margin-top: 1rem;
  flex-direction: column;
}

@media (min-width: 640px) {
  .CalendarWrapper {
    margin-left: 1rem;
    margin-top: 0;
    flex-direction: row;
  }
}

.CalendarGrid {
  margin-top: 0.25rem;
  width: 100%;
  user-select: none;
  border-collapse: collapse;
}

.CalendarGridRow {
  display: grid;
  margin-bottom: 0.25rem;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  width: 100%;
}

.CalendarGridRow[data-reka-calendar-month-view] {
  grid-template-columns: repeat(8, minmax(0, 1fr));
}

.CalendarHeadCell {
  border-radius: 0.375rem;
  font-size: 0.75rem;
  line-height: 1rem;
  color: #000000;
  font-weight: 400;
}

.CalendarWeek {
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 0.875rem;
  line-height: 1.25rem;
}

.CalendarCell {
  position: relative;
  font-size: 0.875rem;
  line-height: 1.25rem;
  text-align: center;
}

.CalendarCellTrigger {
  display: flex;
  position: relative;
  padding: 0.5rem;
  justify-content: center;
  align-items: center;
  border-width: 1px;
  border-color: transparent;
  outline-style: none;
  font-size: 0.875rem;
  line-height: 1.25rem;
  font-weight: 400;
  color: #000000;
  white-space: nowrap;
  background-color: transparent;
}

.CalendarCellTrigger:hover {
  border-color: #000000;
}

.CalendarCellTrigger:focus {
  box-shadow: 0 0 0 2px #000000;
}

.CalendarCellTrigger[data-disabled] {
  cursor: none;
  color: rgba(0,0,0,0.3);
}

.CalendarCellTrigger[data-selected] {
  background-color: #000000;
  color: #ffffff;
  font-weight: 500;
}

.CalendarCellTrigger[data-selected]::before {
  background-color: #FFFFFF;
}

.CalendarCellTrigger[data-unavailable] {
  color: rgba(0,0,0,0.3);
  text-decoration: line-through;
}

.CalendarCellTrigger::before {
  content: '';
  position: absolute;
  top: 5px;
  left: 0;
  width: 0.25rem;
  height: 0.25rem;
  border-radius: 9999px;
  background-color: #FFFFFF;
}

.CalendarCellTrigger[data-today]::before {
  display: block;
  background-color: var(--grass-9);
}

/* reset */
button {
  all: unset;
}
}
```

## Accessibility

### Keyboard Interactions

| Key | Description |
| --- | --- |
| <kbd>Tab</kbd> | When focus moves onto the calendar, focuses the first navigation button. |
| <kbd>Space</kbd> |  When the focus is on either `CalendarNext` or `CalendarPrev`, it navigates the calendar. Otherwise, it selects the date.  |
| <kbd>Enter</kbd> |  When the focus is on either `CalendarNext` or `CalendarPrev`, it navigates the calendar. Otherwise, it selects the date.  |
| <kbd>ArrowLeft</kbd> / <kbd>ArrowRight</kbd> / <kbd>ArrowUp</kbd> / <kbd>ArrowDown</kbd> | When the focus is on `CalendarCellTrigger`, it navigates the dates, changing the month/year/decade if necessary. |
| <kbd>Home</kbd> | When the focus is on `CalendarCellTrigger`, it moves focus to the first day of the current week. |
| <kbd>End</kbd> | When the focus is on `CalendarCellTrigger`, it moves focus to the last day of the current week. |
| <kbd>PageUp</kbd> | When the focus is on `CalendarCellTrigger`, it moves to the previous month while preserving the day of the month when possible, or clamps to the last day of the month. |
| <kbd>PageDown</kbd> | When the focus is on `CalendarCellTrigger`, it moves to the next month while preserving the day of the month when possible, or clamps to the last day of the month. |
| <kbd>Shift+PageUp</kbd> | When the focus is on `CalendarCellTrigger`, it moves to the previous year while preserving the month and day when possible, or clamps to the last day of the month. |
| <kbd>Shift+PageDown</kbd> | When the focus is on `CalendarCellTrigger`, it moves to the next year while preserving the month and day when possible, or clamps to the last day of the month. |

---

- [GitHub](https://github.com/vinicunca/akar/blob/v2.0.20/packages/core/src/Calendar)
- [npm](https://www.npmjs.com/package/akar)


## Sitemap

See the full [sitemap](https://vinicunca.dev/sitemap.md) for all pages.
