Calendar
Date picker with month grid, navigation, and year picker support built on Reka UI's Calendar.
Usage
<script setup lang="ts">
import { Calendar } from '@hareui/vue'
</script>| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 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 |
<script setup lang="ts">import { Calendar } from '@hareui/vue'</script><template> <Calendar aria-label="Event date" /></template>Anatomy
Calendar renders a header (heading or year-picker trigger, plus previous/next buttons) followed by a 7-column day grid, with an optional overlay year grid.
<template>
<Calendar aria-label="Event date">
<template #navIcon="{ direction }" /> <!-- replaces both chevrons -->
<template #cell="{ date, today, selected, disabled, unavailable, outsideView }" /> <!-- replaces formatted day -->
</Calendar>
</template>ui key | data-slot | Element |
|---|---|---|
base | calendar | root element |
header | calendar-header | row containing the heading/year-picker trigger and nav buttons |
heading | calendar-heading | formatted month/year label (hidden when year-picker) |
navButton | calendar-nav-button | previous/next button |
navButtonIcon | calendar-nav-button-icon | default chevron inside a nav button |
grid | calendar-grid | the day grid |
gridHeader | calendar-grid-header | weekday label row wrapper |
gridBody | calendar-grid-body | week rows wrapper |
gridRow | – | one week row |
headerCell | calendar-header-cell | weekday label cell |
cell | calendar-cell | one interactive day |
cellIndicator | calendar-cell-indicator | dot rendered when indicator(date) is true |
yearPickerTrigger | calendar-year-picker-trigger | toggles the year grid (when year-picker) |
yearPickerTriggerHeading | calendar-year-picker-trigger-heading | heading text inside the trigger |
yearPickerTriggerIndicator | calendar-year-picker-trigger-indicator | chevron icon inside the trigger |
yearPickerGrid | calendar-year-picker-grid | overlay grid of selectable years |
yearPickerYearCell | calendar-year-picker-year-cell | one selectable year |
Examples
Default Value
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
26 | 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 | 1 |
<script setup lang="ts">import { Calendar } from '@hareui/vue'import { parseDate } from '@internationalized/date'</script><template> <Calendar aria-label="Event date" :default-value="parseDate('2025-02-14')" /></template>Disabled
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 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 |
<script setup lang="ts">import { Calendar, Description } from '@hareui/vue'import { getLocalTimeZone, today } from '@internationalized/date'</script><template> <div class="flex flex-col items-center gap-4"> <Calendar aria-label="Event date" :default-value="today(getLocalTimeZone())" disabled /> <Description class="text-center"> Calendar is disabled </Description> </div></template>Read Only
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 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 |
<script setup lang="ts">import { Calendar, Description } from '@hareui/vue'import { getLocalTimeZone, today } from '@internationalized/date'</script><template> <div class="flex flex-col items-center gap-4"> <Calendar aria-label="Event date" :default-value="today(getLocalTimeZone())" readonly /> <Description class="text-center"> Calendar is read-only </Description> </div></template>Year Picker
Set year-picker to replace the plain heading with a toggleable overlay grid of years, bounded by min-value/max-value (defaulting to 1900–2099).
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 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 |
<script setup lang="ts">import { Calendar } from '@hareui/vue'</script><template> <Calendar aria-label="Event date" year-picker /></template>Controlled
Use v-model and v-model:placeholder for external state coordination and custom shortcuts.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
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 |
<script setup lang="ts">import type { DateValue } from '@internationalized/date'import { Button, ButtonGroup, Calendar, Description } from '@hareui/vue'import { getLocalTimeZone, parseDate, startOfMonth, startOfWeek, today } from '@internationalized/date'import { shallowRef } from 'vue'const value = shallowRef<DateValue | null>(null)const focusedDate = shallowRef<DateValue>(parseDate('2025-12-25'))</script><template> <div class="flex flex-col items-center gap-4"> <ButtonGroup full-width size="sm" variant="tertiary"> <Button @click="() => { const todayDate = today(getLocalTimeZone()) value = todayDate focusedDate = todayDate }" > Today </Button> <Button @click="() => { const nextWeekStart = startOfWeek(today(getLocalTimeZone()), 'en-US') value = nextWeekStart focusedDate = nextWeekStart }" > Week </Button> <Button @click="() => { const nextMonthStart = startOfMonth(today(getLocalTimeZone())) value = nextMonthStart focusedDate = nextMonthStart }" > Month </Button> </ButtonGroup> <Calendar aria-label="Event date" v-model="value" v-model:placeholder="focusedDate" /> <Description class="text-center"> Selected date: {{ value ? value.toString() : '(none)' }} </Description> <div class="flex gap-2"> <Button size="sm" variant="secondary" @click="() => { const todayDate = today(getLocalTimeZone()) value = todayDate focusedDate = todayDate }" > Set Today </Button> <Button size="sm" variant="secondary" @click="() => { const christmasDate = parseDate('2025-12-25') value = christmasDate focusedDate = christmasDate }" > Set Christmas </Button> <Button size="sm" variant="tertiary" @click="value = null"> Clear </Button> </div> </div></template>Min and Max Dates
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 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 |
<script setup lang="ts">import { Calendar, Description } from '@hareui/vue'import { getLocalTimeZone, today } from '@internationalized/date'const now = today(getLocalTimeZone())const minDate = nowconst maxDate = now.add({ months: 3 })</script><template> <div class="flex flex-col items-center gap-4"> <Calendar aria-label="Appointment date" :min-value="minDate" :max-value="maxDate" /> <Description class="text-center"> Select a date between today and {{ maxDate.toString() }} </Description> </div></template>Unavailable Dates
Use is-date-unavailable to block dates such as weekends, holidays, or booked slots.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 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 |
<script setup lang="ts">import type { DateValue } from '@internationalized/date'import { Calendar, Description } from '@hareui/vue'import { isWeekend } from '@internationalized/date'function isDateUnavailable(date: DateValue) { return isWeekend(date, 'en-US')}</script><template> <div class="flex flex-col items-center gap-4"> <Calendar aria-label="Appointment date" :is-date-unavailable="isDateUnavailable" /> <Description class="text-center"> Weekends are unavailable </Description> </div></template>Weeks in Month
Set fixed-weeks to always render 6 weeks, keeping the grid height stable when navigating between months.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 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 |
<script setup lang="ts">import { Calendar, Description } from '@hareui/vue'</script><template> <div class="flex flex-col items-center gap-4"> <Calendar aria-label="Event date" fixed-weeks /> <Description class="text-center"> Always shows 6 weeks per month to avoid layout shift when navigating </Description> </div></template>Week View
Set visible-duration to { weeks: n } to show one or more weeks at a time. Navigation advances by the visible week range. Use page-behavior="single" to move one week at a time when showing multiple weeks.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 28 | 29 | 30 | 1 | 2 | 3 |
<script setup lang="ts">import type { ListBoxItem } from '@hareui/vue'import { Calendar, Select } from '@hareui/vue'import { ref } from 'vue'const weekOptions: ListBoxItem[] = [ { value: '1', label: '1 week' }, { value: '2', label: '2 weeks' }, { value: '3', label: '3 weeks' }, { value: '4', label: '4 weeks' }, { value: '5', label: '5 weeks' }, { value: '6', label: '6 weeks' }, { value: '8', label: '8 weeks' },]const weeks = ref(1)</script><template> <div class="flex flex-col items-center gap-6"> <Select class="w-40" label="Visible weeks" :items="weekOptions" :model-value="String(weeks)" @update:model-value="(value) => value && (weeks = Number(value))" /> <Calendar aria-label="Week view" :visible-duration="{ weeks }" /> </div></template>Day View
Set visible-duration to { days: n } to show a rolling window of consecutive days. Navigation advances by the visible day range. Use page-behavior="single" to move one day at a time when showing multiple days.
| Thu | Fri | Sat | Sun | Mon |
|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 |
<script setup lang="ts">import type { ListBoxItem } from '@hareui/vue'import { Calendar, Select } from '@hareui/vue'import { ref } from 'vue'const dayOptions: ListBoxItem[] = [ { value: '1', label: '1 day' }, { value: '5', label: '5 days' }, { value: '7', label: '7 days' }, { value: '8', label: '8 days' }, { value: '10', label: '10 days' }, { value: '14', label: '14 days' }, { value: '21', label: '21 days' },]const days = ref(5)</script><template> <div class="flex flex-col items-center gap-6"> <Select class="w-40" label="Visible days" :items="dayOptions" :model-value="String(days)" @update:model-value="(value) => value && (days = Number(value))" /> <Calendar aria-label="Day view" :visible-duration="{ days }" /> </div></template>Multiple Selection
Set selection-mode="multiple" to let users select several dates. model-value and default-value become an array of dates.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
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 |
<script setup lang="ts">import type { DateValue } from '@internationalized/date'import { Calendar, Description } from '@hareui/vue'import { shallowRef } from 'vue'const value = shallowRef<DateValue[]>([])</script><template> <div class="flex flex-col items-center gap-4"> <Calendar aria-label="Event dates" selection-mode="multiple" :model-value="value" @update:model-value="v => value = v as DateValue[]" /> <Description class="text-center"> {{ value.length ? `${value.length} date(s) selected` : 'Select multiple dates' }} </Description> </div></template>Focused Value
Programmatically control which month is displayed using v-model:placeholder.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
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 |
<script setup lang="ts">import type { DateValue } from '@internationalized/date'import { Button, Calendar, Description } from '@hareui/vue'import { parseDate } from '@internationalized/date'import { shallowRef } from 'vue'const focusedDate = shallowRef<DateValue>(parseDate('2025-06-15'))</script><template> <div class="flex flex-col items-center gap-4"> <Calendar aria-label="Event date" v-model:placeholder="focusedDate" /> <Description class="text-center"> Focused: {{ focusedDate.toString() }} </Description> <div class="flex flex-wrap justify-center gap-2"> <Button size="sm" variant="secondary" @click="focusedDate = parseDate('2025-01-01')"> Go to Jan </Button> <Button size="sm" variant="secondary" @click="focusedDate = parseDate('2025-06-15')"> Go to Jun </Button> <Button size="sm" variant="secondary" @click="focusedDate = parseDate('2025-12-25')"> Go to Christmas </Button> </div> </div></template>Cell Indicators
Pass indicator to render a dot under matching dates, e.g. to surface metadata like events.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 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 |
<script setup lang="ts">import type { DateValue } from '@internationalized/date'import { getLocalTimeZone, isToday } from '@internationalized/date'import { Calendar } from '@hareui/vue'const datesWithEvents = [3, 7, 12, 15, 21, 28]function indicator(date: DateValue) { return isToday(date, getLocalTimeZone()) || datesWithEvents.includes(date.day)}</script><template> <Calendar aria-label="Event date" :indicator="indicator" /></template>Custom Navigation Icons
Use the #navIcon slot to replace the default chevron icons.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 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 |
<script setup lang="ts">import { Calendar } from '@hareui/vue'</script><template> <Calendar aria-label="Event date"> <template #navIcon="{ direction }"> <span class="text-xs font-bold">{{ direction === 'previous' ? '«' : '»' }}</span> </template> </Calendar></template>Real-World Example
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 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 |
<script setup lang="ts">import type { CalendarDate, DateValue } from '@internationalized/date'import { Button, Calendar } from '@hareui/vue'import { getLocalTimeZone, isWeekend, today } from '@internationalized/date'import { computed, shallowRef } from 'vue'const selectedDate = shallowRef<CalendarDate | null>(null)const bookedDates = [5, 6, 12, 13, 14, 20]function isDateUnavailable(date: DateValue) { return isWeekend(date, 'en-US') || bookedDates.includes(date.day)}function indicator(date: DateValue) { return !isWeekend(date, 'en-US') && bookedDates.includes(date.day)}const minValue = computed(() => today(getLocalTimeZone()))</script><template> <div class="flex flex-col items-center gap-4"> <Calendar aria-label="Booking date" v-model="selectedDate" :is-date-unavailable="isDateUnavailable" :min-value="minValue" :indicator="indicator" /> <div class="flex flex-col gap-2 text-center"> <div class="flex items-center justify-center gap-4 text-xs text-muted"> <span class="flex items-center gap-1"> <span class="size-2 rounded-full bg-muted" /> Has bookings </span> <span class="flex items-center gap-1"> <span class="size-2 rounded-full bg-default" /> Weekend/Unavailable </span> </div> <Button v-if="selectedDate" size="sm" variant="primary"> Book {{ selectedDate.toString() }} </Button> </div> </div></template>International Calendars
By default, Calendar displays dates using the calendar system for the given locale. The example below shows the Indian calendar system.
| रवि | सोम | मंगल | बुध | गुरु | शुक्र | शनि |
|---|---|---|---|---|---|---|
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 |
<script setup lang="ts">import type { CalendarIdentifier } from '@internationalized/date'import { createCalendar, getLocalTimeZone, today, toCalendar } from '@internationalized/date'import { Calendar } from '@hareui/vue'const locale = 'hi-IN-u-ca-indian'const calendarId = new Intl.DateTimeFormat(locale).resolvedOptions().calendar as CalendarIdentifierconst defaultValue = toCalendar(today(getLocalTimeZone()), createCalendar(calendarId))</script><template> <Calendar aria-label="Event date" :locale="locale" :default-value="defaultValue" year-picker /></template>Note: update:modelValue always emits a date in the same calendar system as model-value or default-value (Gregorian if neither is given), regardless of the displayed locale.
Multiple Months
Set number-of-months to show several months side by side. The previous/next buttons always page by the full visible width, matching React Aria's default behavior for multi-month calendars.
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 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 |
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
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 |
<script setup lang="ts">import { Calendar } from '@hareui/vue'</script><template> <Calendar aria-label="Trip dates" class="@container-normal w-full max-w-none overflow-x-auto" :number-of-months="2" /></template>Customization
Tailwind CSS
| Sun | Mon | Tue | Wed | Thu | Fri | Sat |
|---|---|---|---|---|---|---|
27 | 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 |
<script setup lang="ts">import { Calendar } from '@hareui/vue'</script><template> <Calendar aria-label="Custom styled calendar" class="w-63 rounded-2xl border border-border/80 bg-surface p-3 shadow-sm ring-1 ring-accent/5 dark:border-border/90 dark:ring-accent/10" /></template>Global Configuration
To customize the Calendar classes for the whole app, extend the calendar theme in createHareUI:
app.use(createHareUI({
ui: {
calendar: {
slots: {
base: 'rounded-2xl border border-border bg-surface p-3 shadow-sm',
cell: 'rounded-lg',
},
},
},
}))Styling Reference
Interactive States
Calendar sets these data attributes (from Reka UI):
- Selected:
[data-selected]on[data-slot="calendar-cell"] - Today:
[data-today] - Unavailable:
[data-unavailable] - Outside the visible month:
[data-outside-view] - Hover:
:hover - Press:
:active - Focus visible:
:focus-visible - Disabled:
:disabledor[data-disabled]
Reka UI Limitations
- Week and day views (
visible-duration) are rendered by HareUI's own grid, since Reka'sCalendarRoot/RangeCalendarRootalways build full month grids. They follow React Aria'svisibleDurationbehaviour (alignment, paging,page-behavior, keyboard navigation) and HeroUI's--week-view/--day-viewstyles; the year picker,number-of-monthsandfixed-weeksonly apply to the month view. fixed-weeksis boolean only (always 6 weeks). HeroUI's ReactweeksInMonthaccepts any count up to 6; Reka'sCalendarRootonly exposes the all-or-nothingfixedWeeksflag.
API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
ariaLabel | string | - | Accessible label for the calendar. |
modelValue | DateValue | DateValue[] | null | undefined | The selected date(s). Use v-model to control it. |
defaultValue | DateValue | DateValue[] | - | The selected date(s) when initially rendered (uncontrolled).
Reka UI's defaultValue prop type only accepts a single DateValue, not an array, even in
multiple-selection mode (see reka-limitations in the Calendar report); cast at the call site. |
placeholder | DateValue | undefined | The currently displayed month/year. Use v-model:placeholder to control it. |
defaultPlaceholder | DateValue | - | The date initially displayed, before navigation (uncontrolled). |
minValue | DateValue | 1900-01-01 | The minimum selectable date. |
maxValue | DateValue | 2099-12-31 | The maximum selectable date. |
isDateUnavailable | ((date: DateValue) => boolean) | - | Callback returning whether a given date is unavailable for selection. |
disabled | boolean | false | Whether the whole calendar is disabled. |
readonly | boolean | false | Whether the calendar is read-only (dates stay visible but cannot be changed). |
locale | string | - | The locale used for formatting and week calculations. |
firstDayOfWeek | "sun" | "mon" | "tue" | "wed" | "thu" | "fri" | "sat" | - | The day the week starts on. |
fixedWeeks | boolean | false | Whether to always display 6 weeks, avoiding layout shift between months.
Reka UI only supports a fixed 6-week grid (HeroUI's React weeksInMonth accepts
any count up to 6; see reka-limitations in the Calendar report). |
selectionMode | "multiple" | "single" | "single" | Whether one or multiple dates can be selected. |
yearPicker | boolean | false | Replaces the plain month/year heading with a toggleable year grid. |
indicator | ((date: DateValue) => boolean) | - | Callback returning whether a small dot indicator should render under a date. |
pagedNavigation | boolean | false | This property causes the previous/next buttons to navigate by the number of months displayed at once rather than one month. |
numberOfMonths | number | 1 | Shows this many months side by side. Navigating with the prev/next buttons always pages
by the full visible width (Reka's pagedNavigation, forced on regardless of the
pagedNavigation prop, matching React Aria's default pageBehavior: "visible").
Reka's heading only formats the combined range, so each panel renders its own
"<Month> <Year>" label derived from that panel's Grid.value (see reka-limitations in
the Calendar report). |
invalid | boolean | false | Marks the calendar as invalid for consumer-driven validation. Reka's own isInvalid is a
read-only computed derived from isDateUnavailable/minValue/maxValue, with no input prop
to override it (see reka-limitations in the Calendar report), so this sets
aria-invalid/data-invalid directly instead. HeroUI's styles don't key off it either, so
it has no visual effect by itself. |
dir | "ltr" | "rtl" | - | The reading direction of the calendar. |
visibleDuration | VisibleDuration | { months: 1 } | The visible time range. { weeks: n } shows a week view and { days: n } a day view (a rolling window of
consecutive days); anything else shows the month view (use number-of-months for several months).
Navigation advances by the visible range. |
pageBehavior | PageBehavior | "visible" | In week/day views, whether the prev/next buttons and page keys move by the whole visible range
('visible') or by one week/day ('single'). |
ui | ComponentSlots<{ slots: { base: string; panels: string; panel: string; header: string[]; heading: string; navButton: string[]; navButtonIcon: string; grid: string[]; gridHeader: string; gridBody: string; gridRow: string; headerCell: string; cell: string[]; cellIndicator: string; yearPickerTrigger: string[]; yearPickerTriggerHeading: string[]; yearPickerTriggerIndicator: string[]; yearPickerGrid: string[]; yearPickerYearCell: string[]; }; variants: { view: { month: {}; week: { cell: string; }; day: { cell: string; grid: string; gridHeader: string; gridBody: string; }; }; }; defaultVariants: { view: string; }; }> | - | Per-slot class overrides. |
Slots
| Slot | Props | Description |
|---|---|---|
navIcon | { direction: "previous" | "next"; } | Replaces the chevron icon inside a nav button. |
cell | { date: DateValue; today: boolean; selected: boolean; disabled: boolean; unavailable: boolean; outsideView: boolean; } | Replaces a cell's default formatted-date content. |
Emits
| Event | Payload | Description |
|---|---|---|
update:modelValue | [value: DateValue | DateValue[] | undefined] | - |
update:placeholder | [value: DateValue] | - |