| 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 |
<script setup lang="ts">
import type { DateValue } from 'akar';
import { ARangeCalendarCell, ARangeCalendarCellTrigger, ARangeCalendarGrid, ARangeCalendarGridBody, ARangeCalendarGridHead, ARangeCalendarGridRow, ARangeCalendarHeadCell, ARangeCalendarHeader, ARangeCalendarHeading, ARangeCalendarNext, ARangeCalendarPrev, ARangeCalendarRoot } from 'akar';
function isDateUnavailable(date: DateValue) {
return date.day === 17 || date.day === 18;
}
</script>
<template>
<ARangeCalendarRoot
v-slot="{ weekDays, grid }"
:is-date-unavailable="isDateUnavailable"
fixed-weeks
>
<ARangeCalendarHeader class="flex items-center justify-between">
<ARangeCalendarPrev
class="text-sm color-text font-medium p-1.5 rounded-md inline-flex gap-1.5 items-center focus-visible:bg-background-elevated hover:bg-background-elevated"
>
<i
class="i-lucide:chevron-left h-4 w-4"
/>
</ARangeCalendarPrev>
<ARangeCalendarHeading class="text-sm font-medium mx-auto text-center truncate" />
<ARangeCalendarNext
class="text-sm color-text font-medium p-1.5 rounded-md inline-flex gap-1.5 items-center focus-visible:bg-background-elevated hover:bg-background-elevated"
>
<i
class="i-lucide:chevron-right h-4 w-4"
/>
</ARangeCalendarNext>
</ARangeCalendarHeader>
<div
class="pt-4 flex flex-col space-y-4 sm:(flex-row space-x-4 space-y-0)"
>
<ARangeCalendarGrid
v-for="month in grid"
:key="month.value.toString()"
class="w-full select-none border-collapse space-y-1 focus:outline-none"
>
<ARangeCalendarGridHead>
<ARangeCalendarGridRow class="mb-1 grid grid-cols-7 w-full">
<ARangeCalendarHeadCell
v-for="day in weekDays"
:key="day"
class="text-xs color-primary rounded-md"
>
{{ day }}
</ARangeCalendarHeadCell>
</ARangeCalendarGridRow>
</ARangeCalendarGridHead>
<ARangeCalendarGridBody class="grid">
<ARangeCalendarGridRow
v-for="(weekDates, index) in month.rows"
:key="`weekDate-${index}`"
class="grid grid-cols-7 place-items-center"
>
<ARangeCalendarCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
class="text-sm text-center relative"
>
<ARangeCalendarCellTrigger
:day="weekDate"
:month="month.value"
class="m-0.5 rounded-full flex size-8 whitespace-nowrap transition-colors-280 items-center justify-center relative data-[disabled]:(color-text-dimmed cursor-not-allowed) data-[outside-view]:color-text-muted data-[unavailable]:(color-text-muted line-through pointer-events-none) data-[today]:font-semibold focus:outline-none data-[highlighted]:bg-primary/20 focus-visible:ring-2 focus-visible:ring-primary data-[today]:not-[[data-selected]]:color-primary hover:not-[[data-selected]]:bg-primary/20 akar:data-[selected]:color-text-inverted akar:data-[selected]:bg-primary"
/>
</ARangeCalendarCell>
</ARangeCalendarGridRow>
</ARangeCalendarGridBody>
</ARangeCalendarGrid>
</div>
</ARangeCalendarRoot>
</template>
The component depends on the @internationalized/date 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.
Import all parts and piece them together.
<script setup>
import {
ARangeCalendarCell,
ARangeCalendarCellTrigger,
ARangeCalendarGrid,
ARangeCalendarGridBody,
ARangeCalendarGridHead,
ARangeCalendarGridRow,
ARangeCalendarHeadCell,
ARangeCalendarHeader,
ARangeCalendarHeading,
ARangeCalendarNext,
ARangeCalendarPrev,
ARangeCalendarRoot,
} from 'akar';
</script>
<template>
<ARangeCalendarRoot>
<ARangeCalendarHeader>
<ARangeCalendarPrev />
<ARangeCalendarHeading />
<ARangeCalendarNext />
</ARangeCalendarHeader>
<ARangeCalendarGrid>
<ARangeCalendarGridHead>
<ARangeCalendarGridRow>
<ARangeCalendarHeadCell />
</ARangeCalendarGridRow>
</ARangeCalendarGridHead>
<ARangeCalendarGridBody>
<ARangeCalendarGridRow>
<ARangeCalendarCell>
<ARangeCalendarCellTrigger />
</ARangeCalendarCell>
</ARangeCalendarGridRow>
</ARangeCalendarGridBody>
</ARangeCalendarGrid>
</ARangeCalendarRoot>
</template>
One benefit of using Akar is its flexibility and low-level control over the components. However, this also means that you may need to manually construct more complex UI elements by combining multiple Akar components together.
If you feel there's a lot of elements that needs to be constructed manually using Akar, consider using Pohon UI instead. It provides a higher-level abstraction over Akar components with pre-defined styles and behaviors that can help you build UIs faster.
Contains all the parts of a calendar
| Prop | Default | Type |
|---|---|---|
as | 'div' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
allowNonContiguousRanges | false | booleanWhen combined with |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
calendarLabel | stringThe accessible label for the calendar | |
defaultPlaceholder | DateValueThe default placeholder date | |
defaultValue | { start: undefined, end: undefined } | DateRangeThe default value for the calendar |
dir | 'ltr' | 'rtl'The reading direction of the calendar when applicable. | |
disabled | false | booleanWhether or not the calendar is disabled |
disableDaysOutsideCurrentView | false | booleanWhether or not to disable days outside the current view. |
fixedDate | 'start' | 'end'Which part of the range should be fixed | |
fixedWeeks | false | boolean |
initialFocus | false | booleanIf 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 | DateMatcherA function that returns whether or not a date is disabled | |
isDateHighlightable | DateMatcherA function that returns whether or not a date is hightable | |
isDateUnavailable | DateMatcherA function that returns whether or not a date is unavailable | |
locale | string | |
maximumDays | numberThe maximum number of days that can be selected in a range | |
maxValue | DateValueThe maximum date that can be selected | |
minValue | DateValueThe minimum date that can be selected | |
modelValue | DateRange | null | |
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 | numberThe number of months to display at once |
pagedNavigation | false | booleanThis property causes the previous and next buttons to navigate by the number of months displayed at once, rather than one month |
placeholder | DateValueThe placeholder date, which is used to determine what month to display when no date is selected. This updates as the user navigates the calendar and can be used to programmatically control the calendar view | |
preventDeselect | false | booleanWhether 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 | booleanWhether or not the calendar is readonly |
weekdayFormat | 'narrow' | 'narrow' | 'long' | 'short'The format to use for the weekday strings provided via the weekdays slot prop |
weekStartsOn | 0 | 0 | 1 | 2 | 3 | 4 | 5 | 6 |
| Event | Type |
|---|---|
update:modelValue | [date: DateRange]Event handler called whenever the model value changes |
update:placeholder | [date: DateValue]Event handler called whenever the placeholder value changes |
update:startValue | [date: DateValue]Event handler called whenever the start value changes |
update:validModelValue | [date: DateRange]Event handler called whenever there is a new validModel |
| Slot | Type |
|---|---|
date | DateValueThe current date of the placeholder |
grid | DateGrid<DateValue>The grid of dates |
weekDays | string[]The days of the week |
weekStartsOn | 0 | 1 | 2 | 3 | 4 | 5 | 6The day of the week to start the calendar on |
locale | stringThe locale to use for formatting dates |
fixedWeeks | booleanWhether or not to always display 6 weeks in the calendar |
modelValue | DateRangeThe controlled checked state of the calendar. Can be bound as |
| Attribute | Value |
|---|---|
[data-readonly] | Present when readonly |
[data-disabled] | Present when disabled |
[data-invalid] | Present when invalid |
Contains the navigation buttons and the heading segments.
| Prop | Default | Type |
|---|---|---|
as | 'div' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Calendar navigation button. It navigates the calendar one month/year/decade in the past based on the current calendar view.
| Attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
| Prop | Default | Type |
|---|---|---|
as | 'button' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
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. |
| Slot | Type |
|---|---|
disabled | booleanWhether or not the calendar is disabled |
Calendar navigation button. It navigates the calendar one month/year/decade in the future based on the current calendar view.
| Prop | Default | Type |
|---|---|---|
as | 'button' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
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. |
| Slot | Type |
|---|---|
disabled | booleanWhether or not the calendar is disabled |
| Attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
Heading for displaying the current month and year.
| Prop | Default | Type |
|---|---|---|
as | 'div' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
| Slot | Type |
|---|---|
headingValue | stringCurrent month and year |
| Attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
Container for wrapping the calendar grid.
| Prop | Default | Type |
|---|---|---|
as | 'table' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
| Attribute | Value |
|---|---|
[data-readonly] | Present when readonly |
[data-disabled] | Present when disabled |
Container for wrapping the grid head.
| Prop | Default | Type |
|---|---|---|
as | 'thead' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Container for wrapping the grid body.
| Prop | Default | Type |
|---|---|---|
as | 'tbody' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Container for wrapping the grid row.
| Prop | Default | Type |
|---|---|---|
as | 'tr' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Container for wrapping the head cell. Used for displaying the week days.
| Prop | Default | Type |
|---|---|---|
as | 'th' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Container for wrapping the calendar cells.
| Prop | Default | Type |
|---|---|---|
as | 'td' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
date* | DateValue |
| Attribute | Value |
|---|---|
[data-disabled] | Present when disabled |
Interactable container for displaying the cell dates. Clicking it selects the date.
| Prop | Default | Type |
|---|---|---|
as | 'div' | APrimitiveAsTag | ComponentThe element or component this component should render as. Can be overwritten by |
asChild | booleanChange the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
day* | DateValue | |
month* | DateValue |
| Slot | Type |
|---|---|
dayValue | stringCurrent day |
disabled | booleanWhether or not the calendar is disabled |
selected | booleanCurrent selected state |
today | booleanCurrent today state |
outsideView | booleanCurrent outside view state |
outsideVisibleView | booleanCurrent outside visible view state |
unavailable | booleanCurrent unavailable state |
highlighted | booleanCurrent highlighted state |
highlightedStart | booleanCurrent highlighted start state |
highlightedEnd | booleanCurrent highlighted end state |
selectionStart | booleanCurrent selection start state |
selectionEnd | booleanCurrent selection end state |
| 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 |
[data-selection-start] | Present when the date is the start of the selection. |
[data-selection-end] | Present when the date is the end of the selection. |
[data-highlighted] | Present when the date is highlighted by the user as they select a range. |
[data-highlighted-start] | Present when the date is the start of the range that is highlighted by the user. |
[data-highlighted-end] | Present when the date is the end of the range that is highlighted by the user. |
[data-focused] | Present when focused |
| Key | Description |
|---|---|
Tab | When focus moves onto the calendar, focuses the first navigation button. |
Space | When the focus is on either |
Enter | When the focus is on either |
ArrowLeftArrowRightArrowUpArrowDown | When the focus is on |