---
title: "Calendar"
description: "A calendar component for selecting single dates, multiple dates or date ranges."
canonical_url: "https://vinicunca.dev/pohon/components/calendar"
---
# Calendar

> A calendar component for selecting single dates, multiple dates or date ranges.

## Usage

Use the `v-model` directive to control the selected date.

```vue
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'

const value = shallowRef(new CalendarDate(2022, 2, 3))
</script>

<template>
  <PCalendar v-model="value" />
</template>
```

Use the `default-value` prop to set the initial value when you do not need to control its state.

```vue
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'

const defaultValue = shallowRef(new CalendarDate(2022, 2, 6))
</script>

<template>
  <PCalendar :default-value="defaultValue" />
</template>
```

**Nuxt:**

> [!NOTE]
> See: /pohon/getting-started/integrations/i18n/nuxt#locale
> 
> This component uses the `@internationalized/date` package for locale-aware formatting. The date format is determined by the `locale` prop of the App component.

**Vue:**

> [!NOTE]
> See: /pohon/getting-started/integrations/i18n/vue#locale
> 
> This component uses the `@internationalized/date` package for locale-aware formatting. The date format is determined by the `locale` prop of the App component.

### Type

Use the `type` prop to change what the calendar selects. Defaults to `date`.

When using `date`, click the heading to switch from the day view to a month then year view for quick navigation, then drill back down to pick a date.

```vue
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'

const value = shallowRef(new CalendarDate(2022, 2, 1))
</script>

<template>
  <PCalendar type="month" v-model="value" />
</template>
```

Use `type="year"` to render a standalone year picker.

```vue
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'

const value = shallowRef(new CalendarDate(2022, 1, 1))
</script>

<template>
  <PCalendar type="year" v-model="value" />
</template>
```

### Multiple

Use the `multiple` prop to allow multiple selections.

```vue
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'

const value = shallowRef([new CalendarDate(2022, 2, 4), new CalendarDate(2022, 2, 6), new CalendarDate(2022, 2, 8)])
</script>

<template>
  <PCalendar multiple v-model="value" />
</template>
```

### Range

Use the `range` prop to select a range of dates.

```vue
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'

const value = shallowRef({ start: new CalendarDate(2022, 2, 3), end: new CalendarDate(2022, 2, 20) })
</script>

<template>
  <PCalendar range v-model="value" />
</template>
```

The `range` prop also works with `type="month"` and `type="year"`, letting you select a range of months or years.

```vue
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'

const value = shallowRef({ start: new CalendarDate(2022, 2, 1), end: new CalendarDate(2022, 6, 1) })
</script>

<template>
  <PCalendar type="month" range v-model="value" />
</template>
```

### Number Of Months

Use the `numberOfMonths` prop to change the number of months in the calendar.

```vue
<template>
  <PCalendar :number-of-months="3" />
</template>
```

### Month Controls

Use the `month-controls` prop to show the month controls. Defaults to `true`.

```vue
<template>
  <PCalendar :month-controls="false" />
</template>
```

Use the `prev-month` and `next-month` props to override the month buttons.

```vue
<template>
  <PCalendar :prev-month="{
  color: 'primary',
  variant: 'soft'
}" :next-month="{
  color: 'primary',
  variant: 'soft'
}" />
</template>
```

### Year Controls

Use the `year-controls` prop to show the year controls. Defaults to `true`.

```vue
<template>
  <PCalendar :year-controls="false" />
</template>
```

Use the `prev-year` and `next-year` props to override the year buttons.

```vue
<template>
  <PCalendar :prev-year="{
  color: 'primary',
  variant: 'soft'
}" :next-year="{
  color: 'primary',
  variant: 'soft'
}" />
</template>
```

### View Control

Use the `view-control` prop to make the heading a button that switches between the day, month and year views. Defaults to `true`.

```vue
<template>
  <PCalendar :view-control="false" />
</template>
```

Set the `view-control` prop to an object to override the heading button.

```vue
<template>
  <PCalendar :view-control="{
  color: 'primary',
  variant: 'soft'
}" />
</template>
```

### Years Per Page

Use the `years-per-page` prop to change the number of years displayed in the year view. Defaults to `12`.

```vue
<template>
  <PCalendar type="year" :years-per-page="20" />
</template>
```

### Fixed Weeks

Use the `fixed-weeks` prop to display the calendar with fixed weeks.

```vue
<template>
  <PCalendar :fixed-weeks="false" />
</template>
```

### Week Numbers

Use the `week-numbers` prop to display week numbers in the calendar.

```vue
<template>
  <PCalendar week-numbers fixed-weeks />
</template>
```

### Color

Use the `color` prop to change the color of the calendar.

```vue
<template>
  <PCalendar color="neutral" />
</template>
```

### Variant

Use the `variant` prop to change the variant of the calendar.

```vue
<template>
  <PCalendar variant="subtle" />
</template>
```

### Size

Use the `size` prop to change the size of the calendar.

```vue
<template>
  <PCalendar size="xl" />
</template>
```

### Disabled

Use the `disabled` prop to disable the calendar.

```vue
<template>
  <PCalendar disabled />
</template>
```

## Examples

### With chip events

Use the [Chip](https://vinicunca.dev/pohon/components/chip) component to add events to specific days.

```vue [CalendarEventsExample.vue]
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date';

const modelValue = shallowRef(new CalendarDate(2022, 1, 10));

function getColorByDate(date: Date) {
  const isWeekend = date.getDay() % 6 == 0;
  const isDayMeeting = date.getDay() % 3 == 0;

  if (isWeekend) {
    return undefined;
  }

  if (isDayMeeting) {
    return 'error';
  }

  return 'success';
}
</script>

<template>
  <PCalendar v-model="modelValue">
    <template #day="{ day }">
      <PChip
        :show="!!getColorByDate(day.toDate('UTC'))"
        :color="getColorByDate(day.toDate('UTC'))"
        size="2xs"
      >
        {{ day.day }}
      </PChip>
    </template>
  </PCalendar>
</template>
```

### With disabled dates

Use the `is-date-disabled` prop with a function to mark specific dates as disabled. When using `type="month"` or `type="year"`, use the `is-month-disabled` or `is-year-disabled` prop instead.

```vue [CalendarDisabledDatesExample.vue]
<script setup lang="ts">
import type { DateValue } from '@internationalized/date';
import { CalendarDate } from '@internationalized/date';

const modelValue = shallowRef({
  start: new CalendarDate(2022, 1, 1),
  end: new CalendarDate(2022, 1, 9),
});

function isDateDisabled(date: DateValue) {
  return date.day >= 10 && date.day <= 16;
}
</script>

<template>
  <PCalendar
    v-model="modelValue"
    :is-date-disabled="isDateDisabled"
    range
  />
</template>
```

### With unavailable dates

Use the `is-date-unavailable` prop with a function to mark specific dates as unavailable. When using `type="month"` or `type="year"`, use the `is-month-unavailable` or `is-year-unavailable` prop instead.

```vue [CalendarUnavailableDatesExample.vue]
<script setup lang="ts">
import type { DateValue } from '@internationalized/date';
import { CalendarDate } from '@internationalized/date';

const modelValue = shallowRef({
  start: new CalendarDate(2022, 1, 1),
  end: new CalendarDate(2022, 1, 9),
});

function isDateUnavailable(date: DateValue) {
  return date.day >= 10 && date.day <= 16;
}
</script>

<template>
  <PCalendar
    v-model="modelValue"
    :is-date-unavailable="isDateUnavailable"
    range
  />
</template>
```

### With min/max dates

Use the `min-value` and `max-value` props to limit the dates.

```vue [CalendarMinMaxDatesExample.vue]
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date';

const modelValue = shallowRef(new CalendarDate(2023, 9, 10));
const minDate = new CalendarDate(2023, 9, 1);
const maxDate = new CalendarDate(2023, 9, 30);
</script>

<template>
  <PCalendar
    v-model="modelValue"
    :min-value="minDate"
    :max-value="maxDate"
  />
</template>
```

### With other calendar systems

You can use other calenders from `@internationalized/date` to implement a different calendar system.

```vue [CalendarOtherSystemExample.vue]
<script lang="ts" setup>
import { CalendarDate, HebrewCalendar } from '@internationalized/date';

const hebrewDate = shallowRef(new CalendarDate(new HebrewCalendar(), 5781, 1, 1));
</script>

<template>
  <PCalendar v-model="hebrewDate" />
</template>
```

> [!NOTE]
> See: https://react-spectrum.adobe.com/internationalized/date/Calendar.html#implementations
> 
> You can check all the available calendars on `@internationalized/date` docs.

### With external controls

You can control the calendar with external controls by manipulating the date passed in the `v-model`.

```vue [CalendarExternalControlsExample.vue]
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date';

const date = shallowRef(new CalendarDate(2025, 4, 2));
</script>

<template>
  <div class="flex flex-col gap-4">
    <PCalendar
      v-model="date"
      :month-controls="false"
      :year-controls="false"
    />

    <div class="flex gap-4 justify-between">
      <PButton
        color="neutral"
        variant="outline"
        @click="date = date.subtract({ months: 1 })"
      >
        Prev
      </PButton>

      <PButton
        color="neutral"
        variant="outline"
        @click="date = date.add({ months: 1 })"
      >
        Next
      </PButton>
    </div>
  </div>
</template>
```

### With today's date

Use the `today` function from `@internationalized/date` with `getLocalTimeZone` to set the value to the current date.

```vue [CalendarTodayExample.vue]
<script setup lang="ts">
import { getLocalTimeZone, today } from '@internationalized/date';

const date = shallowRef(today(getLocalTimeZone()));
</script>

<template>
  <div class="flex flex-col gap-4">
    <PCalendar v-model="date" />

    <PButton
      color="neutral"
      variant="outline"
      class="justify-center"
      @click="date = today(getLocalTimeZone())"
    >
      Today
    </PButton>
  </div>
</template>
```

### As a date picker

Use a [Button](https://vinicunca.dev/pohon/components/button) and a [Popover](https://vinicunca.dev/pohon/components/popover) component to create a date picker.

```vue [CalendarDatePickerExample.vue]
<script setup lang="ts">
import { CalendarDate, DateFormatter, getLocalTimeZone } from '@internationalized/date';

const df = new DateFormatter('en-US', {
  dateStyle: 'medium',
});

const modelValue = shallowRef(new CalendarDate(2022, 1, 10));
</script>

<template>
  <PPopover>
    <PButton
      color="neutral"
      variant="subtle"
      icon="i-lucide-calendar"
    >
      {{ modelValue ? df.format(modelValue.toDate(getLocalTimeZone())) : 'Select a date' }}
    </PButton>

    <template #content>
      <PCalendar
        v-model="modelValue"
        class="p-2"
      />
    </template>
  </PPopover>
</template>
```

### As a date range picker

Use a [Button](https://vinicunca.dev/pohon/components/button) and a [Popover](https://vinicunca.dev/pohon/components/popover) component to create a date range picker with preset ranges.

```vue [CalendarDateRangePickerExample.vue]
<script setup lang="ts">
import { DateFormatter, getLocalTimeZone, today } from '@internationalized/date';
import { useBreakpoints } from '@vueuse/core';

const df = new DateFormatter('en-US', { dateStyle: 'medium' });
const tz = getLocalTimeZone();
const breakpoints = useBreakpoints({ 'sm': 640, 'md': 768, 'lg': 1024, 'xl': 1280, '2xl': 1536 });
const isDesktop = breakpoints.greaterOrEqual('sm');

const ranges = [
  { label: 'Last 7 days', days: 7 },
  { label: 'Last 14 days', days: 14 },
  { label: 'Last 30 days', days: 30 },
  { label: 'Last 3 months', months: 3 },
  { label: 'Last 6 months', months: 6 },
  { label: 'Last year', years: 1 },
];

const initialEnd = today(tz);
const modelValue = shallowRef({
  start: initialEnd.subtract({ days: 14 }),
  end: initialEnd,
});

const label = computed(() => {
  const { start, end } = modelValue.value;
  if (!start) {
    return 'Pick a date';
  }
  if (!end) {
    return df.format(start.toDate(tz));
  }
  return `${df.format(start.toDate(tz))} - ${df.format(end.toDate(tz))}`;
});

function computeStart(range: typeof ranges[number]) {
  const end = today(tz);
  return { start: end.subtract({ days: range.days, months: range.months, years: range.years }), end };
}

function isRangeSelected(range: typeof ranges[number]) {
  if (!modelValue.value?.start || !modelValue.value?.end) {
    return false;
  }
  const { start, end } = computeStart(range);
  return modelValue.value.start.compare(start) === 0 && modelValue.value.end.compare(end) === 0;
}

function selectRange(range: typeof ranges[number]) {
  modelValue.value = computeStart(range);
}
</script>

<template>
  <PPopover :content="{ align: 'center' }">
    <PButton
      color="neutral"
      variant="subtle"
      icon="i-lucide-calendar"
    >
      {{ label }}
    </PButton>

    <template #content>
      <div class="divide---ui-color-border flex items-stretch divide-(x)">
        <div class="py-2 flex-col hidden justify-center sm:flex">
          <PButton
            v-for="(range, index) in ranges"
            :key="index"
            :label="range.label"
            color="neutral"
            variant="ghost"
            class="px-4 rounded-none"
            :class="[isRangeSelected(range) ? 'bg-background-elevated' : 'hover:bg-background-elevated/50']"
            truncate
            @click="selectRange(range)"
          />
        </div>

        <PCalendar
          v-model="modelValue"
          class="p-2"
          :number-of-months="isDesktop ? 2 : 1"
          range
        />
      </div>
    </template>
  </PPopover>
</template>
```

## API

### Props

```ts
/**
 * Props for the Calendar component
 */
interface CalendarProps {
}
```

### Slots

```ts
/**
 * Slots for the Calendar component
 */
interface CalendarSlots {
}
```

### Emits

No events available for this component.

## Theme

```ts [app.config.ts]
export default defineAppConfig({
  ui: {
    calendar: {
      slots: {
        root: '',
        header: 'flex items-center justify-between',
        body: 'pt-4 flex flex-col space-y-4 sm:flex-row sm:space-x-4 sm:space-y-0',
        heading: 'flex-1 min-w-0 text-center',
        headingLabel: 'font-500 block truncate p-1.5',
        grid: 'w-full border-collapse select-none space-y-1 focus:outline-none',
        gridRow: 'grid',
        gridWeekDaysRow: 'mb-1 grid w-full grid-cols-7',
        gridBody: 'grid',
        headCell: 'rounded-md',
        headCellWeek: 'rounded-md color-text-muted',
        cell: 'relative text-center',
        cellTrigger: [
          'data-[disabled]:color-text-muted data-[unavailable]:color-text-muted m-0.5 flex whitespace-nowrap items-center justify-center relative data-[today]:font-600 focus-visible:outline-3 data-[unavailable]:line-through data-[unavailable]:pointer-events-none',
          'transition'
        ],
        cellWeek: 'relative text-center color-text-muted'
      },
      variants: {
        color: {
          primary: {
            headCell: 'color-primary',
            cellTrigger: 'outline-primary/25'
          },
          secondary: {
            headCell: 'color-secondary',
            cellTrigger: 'outline-secondary/25'
          },
          success: {
            headCell: 'color-success',
            cellTrigger: 'outline-success/25'
          },
          info: {
            headCell: 'color-info',
            cellTrigger: 'outline-info/25'
          },
          warning: {
            headCell: 'color-warning',
            cellTrigger: 'outline-warning/25'
          },
          error: {
            headCell: 'color-error',
            cellTrigger: 'outline-error/25'
          },
          neutral: {
            headCell: 'color-text-highlighted',
            cellTrigger: 'outline-border-inverted/25'
          }
        },
        variant: {
          solid: '',
          outline: '',
          soft: '',
          subtle: ''
        },
        size: {
          xs: {
            headingLabel: 'text-xs',
            cell: 'text-xs',
            cellWeek: 'text-xs',
            headCell: 'text-[10px]',
            headCellWeek: 'text-[10px]',
            body: 'space-y-2 pt-2'
          },
          sm: {
            headingLabel: 'text-xs',
            headCell: 'text-xs',
            headCellWeek: 'text-xs',
            cellWeek: 'text-xs',
            cell: 'text-xs'
          },
          md: {
            headingLabel: 'text-sm',
            headCell: 'text-xs',
            headCellWeek: 'text-xs',
            cellWeek: 'text-xs',
            cell: 'text-sm'
          },
          lg: {
            headingLabel: 'text-base',
            headCell: 'text-base',
            headCellWeek: 'text-base',
            cellWeek: 'text-base',
            cell: 'text-base'
          },
          xl: {
            headingLabel: 'text-lg',
            headCell: 'text-lg',
            headCellWeek: 'text-lg',
            cellWeek: 'text-lg',
            cell: 'text-lg'
          }
        },
        view: {
          day: {
            gridRow: 'grid-cols-7 place-items-center',
            cellTrigger: 'data-[outside-view]:color-text-muted rounded-full'
          },
          month: {
            gridRow: 'grid-cols-4',
            cellTrigger: 'rounded-md'
          },
          year: {
            gridRow: 'grid-cols-4',
            cellTrigger: 'rounded-md'
          }
        },
        weekNumbers: {
          true: ''
        }
      },
      compoundVariants: [
        {
          color: 'primary',
          variant: 'solid',
          class: {
            cellTrigger: 'data-[selected]:bg-primary data-[selected]:color-primary-foreground data-[today]:not-data-[selected]:color-primary data-[highlighted]:bg-primary/20 hover:not-data-[selected]:bg-primary/20'
          }
        },
        {
          color: 'secondary',
          variant: 'solid',
          class: {
            cellTrigger: 'data-[selected]:bg-secondary data-[selected]:color-secondary-foreground data-[today]:not-data-[selected]:color-secondary data-[highlighted]:bg-secondary/20 hover:not-data-[selected]:bg-secondary/20'
          }
        },
        {
          color: 'success',
          variant: 'solid',
          class: {
            cellTrigger: 'data-[selected]:bg-success data-[selected]:color-success-foreground data-[today]:not-data-[selected]:color-success data-[highlighted]:bg-success/20 hover:not-data-[selected]:bg-success/20'
          }
        },
        {
          color: 'info',
          variant: 'solid',
          class: {
            cellTrigger: 'data-[selected]:bg-info data-[selected]:color-info-foreground data-[today]:not-data-[selected]:color-info data-[highlighted]:bg-info/20 hover:not-data-[selected]:bg-info/20'
          }
        },
        {
          color: 'warning',
          variant: 'solid',
          class: {
            cellTrigger: 'data-[selected]:bg-warning data-[selected]:color-warning-foreground data-[today]:not-data-[selected]:color-warning data-[highlighted]:bg-warning/20 hover:not-data-[selected]:bg-warning/20'
          }
        },
        {
          color: 'error',
          variant: 'solid',
          class: {
            cellTrigger: 'data-[selected]:bg-error data-[selected]:color-error-foreground data-[today]:not-data-[selected]:color-error data-[highlighted]:bg-error/20 hover:not-data-[selected]:bg-error/20'
          }
        },
        {
          color: 'primary',
          variant: 'outline',
          class: {
            cellTrigger: 'data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-primary/50 data-[selected]:color-primary data-[today]:not-data-[selected]:color-primary data-[highlighted]:bg-primary/10 hover:not-data-[selected]:bg-primary/10'
          }
        },
        {
          color: 'secondary',
          variant: 'outline',
          class: {
            cellTrigger: 'data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-secondary/50 data-[selected]:color-secondary data-[today]:not-data-[selected]:color-secondary data-[highlighted]:bg-secondary/10 hover:not-data-[selected]:bg-secondary/10'
          }
        },
        {
          color: 'success',
          variant: 'outline',
          class: {
            cellTrigger: 'data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-success/50 data-[selected]:color-success data-[today]:not-data-[selected]:color-success data-[highlighted]:bg-success/10 hover:not-data-[selected]:bg-success/10'
          }
        },
        {
          color: 'info',
          variant: 'outline',
          class: {
            cellTrigger: 'data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-info/50 data-[selected]:color-info data-[today]:not-data-[selected]:color-info data-[highlighted]:bg-info/10 hover:not-data-[selected]:bg-info/10'
          }
        },
        {
          color: 'warning',
          variant: 'outline',
          class: {
            cellTrigger: 'data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-warning/50 data-[selected]:color-warning data-[today]:not-data-[selected]:color-warning data-[highlighted]:bg-warning/10 hover:not-data-[selected]:bg-warning/10'
          }
        },
        {
          color: 'error',
          variant: 'outline',
          class: {
            cellTrigger: 'data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-error/50 data-[selected]:color-error data-[today]:not-data-[selected]:color-error data-[highlighted]:bg-error/10 hover:not-data-[selected]:bg-error/10'
          }
        },
        {
          color: 'primary',
          variant: 'soft',
          class: {
            cellTrigger: 'data-[selected]:bg-primary/10 data-[selected]:color-primary data-[today]:not-data-[selected]:color-primary data-[highlighted]:bg-primary/20 hover:not-data-[selected]:bg-primary/20'
          }
        },
        {
          color: 'secondary',
          variant: 'soft',
          class: {
            cellTrigger: 'data-[selected]:bg-secondary/10 data-[selected]:color-secondary data-[today]:not-data-[selected]:color-secondary data-[highlighted]:bg-secondary/20 hover:not-data-[selected]:bg-secondary/20'
          }
        },
        {
          color: 'success',
          variant: 'soft',
          class: {
            cellTrigger: 'data-[selected]:bg-success/10 data-[selected]:color-success data-[today]:not-data-[selected]:color-success data-[highlighted]:bg-success/20 hover:not-data-[selected]:bg-success/20'
          }
        },
        {
          color: 'info',
          variant: 'soft',
          class: {
            cellTrigger: 'data-[selected]:bg-info/10 data-[selected]:color-info data-[today]:not-data-[selected]:color-info data-[highlighted]:bg-info/20 hover:not-data-[selected]:bg-info/20'
          }
        },
        {
          color: 'warning',
          variant: 'soft',
          class: {
            cellTrigger: 'data-[selected]:bg-warning/10 data-[selected]:color-warning data-[today]:not-data-[selected]:color-warning data-[highlighted]:bg-warning/20 hover:not-data-[selected]:bg-warning/20'
          }
        },
        {
          color: 'error',
          variant: 'soft',
          class: {
            cellTrigger: 'data-[selected]:bg-error/10 data-[selected]:color-error data-[today]:not-data-[selected]:color-error data-[highlighted]:bg-error/20 hover:not-data-[selected]:bg-error/20'
          }
        },
        {
          color: 'primary',
          variant: 'subtle',
          class: {
            cellTrigger: 'data-[selected]:bg-primary/10 data-[selected]:color-primary data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-primary/25 data-[today]:not-data-[selected]:color-primary data-[highlighted]:bg-primary/20 hover:not-data-[selected]:bg-primary/20'
          }
        },
        {
          color: 'secondary',
          variant: 'subtle',
          class: {
            cellTrigger: 'data-[selected]:bg-secondary/10 data-[selected]:color-secondary data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-secondary/25 data-[today]:not-data-[selected]:color-secondary data-[highlighted]:bg-secondary/20 hover:not-data-[selected]:bg-secondary/20'
          }
        },
        {
          color: 'success',
          variant: 'subtle',
          class: {
            cellTrigger: 'data-[selected]:bg-success/10 data-[selected]:color-success data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-success/25 data-[today]:not-data-[selected]:color-success data-[highlighted]:bg-success/20 hover:not-data-[selected]:bg-success/20'
          }
        },
        {
          color: 'info',
          variant: 'subtle',
          class: {
            cellTrigger: 'data-[selected]:bg-info/10 data-[selected]:color-info data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-info/25 data-[today]:not-data-[selected]:color-info data-[highlighted]:bg-info/20 hover:not-data-[selected]:bg-info/20'
          }
        },
        {
          color: 'warning',
          variant: 'subtle',
          class: {
            cellTrigger: 'data-[selected]:bg-warning/10 data-[selected]:color-warning data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-warning/25 data-[today]:not-data-[selected]:color-warning data-[highlighted]:bg-warning/20 hover:not-data-[selected]:bg-warning/20'
          }
        },
        {
          color: 'error',
          variant: 'subtle',
          class: {
            cellTrigger: 'data-[selected]:bg-error/10 data-[selected]:color-error data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-error/25 data-[today]:not-data-[selected]:color-error data-[highlighted]:bg-error/20 hover:not-data-[selected]:bg-error/20'
          }
        },
        {
          color: 'neutral',
          variant: 'solid',
          class: {
            cellTrigger: 'data-[selected]:bg-background-inverted data-[selected]:color-text-inverted data-[today]:not-data-[selected]:color-text-highlighted data-[highlighted]:bg-background-inverted/20 hover:not-data-[selected]:bg-background-inverted/10'
          }
        },
        {
          color: 'neutral',
          variant: 'outline',
          class: {
            cellTrigger: 'data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-border-accented data-[selected]:color-text data-[selected]:bg-background data-[today]:not-data-[selected]:color-text-highlighted data-[highlighted]:bg-background-inverted/10 hover:not-data-[selected]:bg-background-inverted/10'
          }
        },
        {
          color: 'neutral',
          variant: 'soft',
          class: {
            cellTrigger: 'data-[selected]:bg-background-elevated data-[selected]:color-text data-[today]:not-data-[selected]:color-text-highlighted data-[highlighted]:bg-background-inverted/20 hover:not-data-[selected]:bg-background-inverted/10'
          }
        },
        {
          color: 'neutral',
          variant: 'subtle',
          class: {
            cellTrigger: 'data-[selected]:bg-background-elevated data-[selected]:color-text data-[selected]:ring data-[selected]:ring-inset data-[selected]:ring-border-accented data-[today]:not-data-[selected]:color-text-highlighted data-[highlighted]:bg-background-inverted/20 hover:not-data-[selected]:bg-background-inverted/10'
          }
        },
        {
          size: 'xs',
          view: 'day',
          class: {
            cellTrigger: 'size-6'
          }
        },
        {
          size: 'sm',
          view: 'day',
          class: {
            cellTrigger: 'size-7'
          }
        },
        {
          size: 'md',
          view: 'day',
          class: {
            cellTrigger: 'size-8'
          }
        },
        {
          size: 'lg',
          view: 'day',
          class: {
            cellTrigger: 'size-9'
          }
        },
        {
          size: 'xl',
          view: 'day',
          class: {
            cellTrigger: 'size-10'
          }
        },
        {
          size: 'xs',
          view: [
            'month',
            'year'
          ],
          class: {
            cellTrigger: 'h-6 px-2'
          }
        },
        {
          size: 'sm',
          view: [
            'month',
            'year'
          ],
          class: {
            cellTrigger: 'h-7 px-2'
          }
        },
        {
          size: 'md',
          view: [
            'month',
            'year'
          ],
          class: {
            cellTrigger: 'h-8 px-3'
          }
        },
        {
          size: 'lg',
          view: [
            'month',
            'year'
          ],
          class: {
            cellTrigger: 'h-9 px-4'
          }
        },
        {
          size: 'xl',
          view: [
            'month',
            'year'
          ],
          class: {
            cellTrigger: 'h-10 px-5'
          }
        },
        {
          view: 'day',
          weekNumbers: true,
          class: {
            gridRow: 'grid-cols-8',
            gridWeekDaysRow: 'grid-cols-8 [&>*:first-child]:col-start-2'
          }
        }
      ],
      defaultVariants: {
        size: 'md',
        color: 'primary',
        variant: 'solid',
        view: 'day'
      }
    }
  }
})
```

## Changelog

See commit history for [component](https://github.com/vinicunca/pohon/commits/main/src/runtime/components/Calendar.vue) and [theme](https://github.com/vinicunca/pohon/commits/main/src/theme/calendar.ts).

---

- [Calendar](https://vinicunca.dev/akar/components/calendar)
- [GitHub](https://github.com/vinicunca/pohon/blob/main/src/runtime/components/Calendar.vue)


## Sitemap

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