Use the v-model directive to control the selected date.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
<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.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
const defaultValue = shallowRef(new CalendarDate(2022, 2, 6))
</script>
<template>
<PCalendar :default-value="defaultValue" />
</template>
@internationalized/date package which provides objects and functions for representing and manipulating dates and times in a locale-aware manner.Use the multiple prop to allow multiple selections.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
<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>
Use the range prop to select a range of dates.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
<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>
Use the color prop to change the color of the calendar.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
<template>
<PCalendar color="neutral" />
</template>
Use the variant prop to change the variant of the calendar.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
<template>
<PCalendar variant="subtle" />
</template>
Use the size prop to change the size of the calendar.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
<template>
<PCalendar size="xl" />
</template>
Use the disabled prop to disable the calendar.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
<template>
<PCalendar disabled />
</template>
Use the numberOfMonths prop to change the number of months in the calendar.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
28 | 29 | 30 | 31 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
1 | 2 | 3 | 4 | 5 | 6 | 7 |
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
<template>
<PCalendar :number-of-months="3" />
</template>
Use the month-controls prop to show the month controls. Defaults to true.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
<template>
<PCalendar />
</template>
Use the year-controls prop to show the year controls. Defaults to true.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
<template>
<PCalendar />
</template>
Use the fixed-weeks prop to display the calendar with fixed weeks.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 1 | 2 | 3 | 4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 | 30 | 31 | 1 | 2 | 3 |
<template>
<PCalendar />
</template>
Use the Chip component to add events to specific days.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date';
import { shallowRef } from 'vue';
const modelValue = shallowRef(new CalendarDate(2025, 10, 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>
Use the is-date-disabled prop with a function to mark specific dates as disabled.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
<script setup lang="ts">
import type { DateValue } from '@internationalized/date';
import { CalendarDate } from '@internationalized/date';
import { shallowRef } from 'vue';
const modelValue = shallowRef({
start: new CalendarDate(2025, 10, 1),
end: new CalendarDate(2025, 10, 9),
});
function isDateDisabled(date: DateValue) {
return date.day >= 10 && date.day <= 16;
}
</script>
<template>
<PCalendar
v-model="modelValue"
:is-date-disabled="isDateDisabled"
range
/>
</template>
Use the is-date-unavailable prop with a function to mark specific dates as unavailable.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
28 | 29 | 30 | 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
<script setup lang="ts">
import type { DateValue } from '@internationalized/date';
import { CalendarDate } from '@internationalized/date';
import { shallowRef } from 'vue';
const modelValue = shallowRef({
start: new CalendarDate(2025, 10, 1),
end: new CalendarDate(2025, 10, 9),
});
function isDateUnavailable(date: DateValue) {
return date.day >= 10 && date.day <= 16;
}
</script>
<template>
<PCalendar
v-model="modelValue"
:is-date-unavailable="isDateUnavailable"
range
/>
</template>
Use the min-value and max-value props to limit the dates.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 31 | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
1 | 2 | 3 | 4 | 5 | 6 | 7 |
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date';
import { shallowRef } from 'vue';
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>
You can use other calenders from @internationalized/date to implement a different calendar system.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
24 | 25 | 26 | 27 | 28 | 29 | 1 |
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 1 | 2 | 3 | 4 | 5 | 6 |
<script lang="ts" setup>
import { CalendarDate, HebrewCalendar } from '@internationalized/date';
import { shallowRef } from 'vue';
const hebrewDate = shallowRef(new CalendarDate(new HebrewCalendar(), 5781, 1, 1));
</script>
<template>
<PCalendar v-model="hebrewDate" />
</template>
You can control the calendar with external controls by manipulating the date passed in the v-model.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date';
import { shallowRef } from 'vue';
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>
| Prop | Default | Type |
|---|
| Slot | Type |
|---|
| Event | Type |
|---|
Below is the theme configuration skeleton for the PCalendar. Since the component is provided unstyled by default, you will need to fill in these values to apply your own custom look and feel. If you prefer to use our pre-built, opinionated styling, you can instead use our UnoCSS preset, this docs is using it as well.
export default defineAppConfig({
pohon: {
calendar: {
slots: {
root: '',
header: '',
body: '',
heading: '',
grid: '',
gridRow: '',
gridWeekDaysRow: '',
gridBody: '',
headCell: '',
cell: '',
cellTrigger: ''
},
variants: {
color: {
primary: {
headCell: '',
cellTrigger: ''
},
secondary: {
headCell: '',
cellTrigger: ''
},
success: {
headCell: '',
cellTrigger: ''
},
info: {
headCell: '',
cellTrigger: ''
},
warning: {
headCell: '',
cellTrigger: ''
},
error: {
headCell: '',
cellTrigger: ''
},
neutral: {
headCell: '',
cellTrigger: ''
}
},
variant: {
solid: '',
outline: '',
soft: '',
subtle: ''
},
size: {
xs: {
heading: '',
cell: '',
headCell: '',
cellTrigger: '',
body: ''
},
sm: {
heading: '',
headCell: '',
cell: '',
cellTrigger: ''
},
md: {
heading: '',
headCell: '',
cell: '',
cellTrigger: ''
},
lg: {
heading: '',
headCell: '',
cellTrigger: ''
},
xl: {
heading: '',
headCell: '',
cellTrigger: ''
}
}
},
defaultVariants: {
size: 'md',
color: 'primary',
variant: 'solid'
}
}
}
};
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import pohon from 'pohon-ui/vite'
export default defineAppConfig({
pohon: {
calendar: {
slots: {
root: '',
header: '',
body: '',
heading: '',
grid: '',
gridRow: '',
gridWeekDaysRow: '',
gridBody: '',
headCell: '',
cell: '',
cellTrigger: ''
},
variants: {
color: {
primary: {
headCell: '',
cellTrigger: ''
},
secondary: {
headCell: '',
cellTrigger: ''
},
success: {
headCell: '',
cellTrigger: ''
},
info: {
headCell: '',
cellTrigger: ''
},
warning: {
headCell: '',
cellTrigger: ''
},
error: {
headCell: '',
cellTrigger: ''
},
neutral: {
headCell: '',
cellTrigger: ''
}
},
variant: {
solid: '',
outline: '',
soft: '',
subtle: ''
},
size: {
xs: {
heading: '',
cell: '',
headCell: '',
cellTrigger: '',
body: ''
},
sm: {
heading: '',
headCell: '',
cell: '',
cellTrigger: ''
},
md: {
heading: '',
headCell: '',
cell: '',
cellTrigger: ''
},
lg: {
heading: '',
headCell: '',
cellTrigger: ''
},
xl: {
heading: '',
headCell: '',
cellTrigger: ''
}
}
},
defaultVariants: {
size: 'md',
color: 'primary',
variant: 'solid'
}
}
}
};
With Pohon UI, you can achieve similar component functionality with less code and effort, as it comes with built-in styles mechanism and behaviors that are optimized for common use cases. Since it's using unocss-variants it adds a runtime cost, but it can be worth it if you prioritize development speed and ease of use over fine-grained control.
If this is a deal breaker for you, you can always stick to using Akar and build your own custom components on top of it.