Range Calendar
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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 |
31 | 1 | 2 | 3 | 4 | 5 | 6 |
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import type { DateValue } from '@internationalized/date'
import { RangeCalendarCell, RangeCalendarCellTrigger, RangeCalendarGrid, RangeCalendarGridBody, RangeCalendarGridHead, RangeCalendarGridRow, RangeCalendarHeadCell, RangeCalendarHeader, RangeCalendarHeading, RangeCalendarNext, RangeCalendarPrev, RangeCalendarRoot } from 'radix-vue'
function isDateUnavailable(date: DateValue) {
return date.day === 17 || date.day === 18
}
</script>
<template>
<RangeCalendarRoot
v-slot="{ weekDays, grid }"
:is-date-unavailable="isDateUnavailable"
class="rounded-xl bg-white p-4 shadow-xl"
fixed-weeks
>
<RangeCalendarHeader class="flex items-center justify-between">
<RangeCalendarPrev
class="inline-flex items-center cursor-pointer text-black justify-center rounded-[9px] bg-transparent w-8 h-8 hover:bg-black hover:text-white active:scale-98 active:transition-all focus:shadow-[0_0_0_2px] focus:shadow-black"
>
<Icon icon="radix-icons:chevron-left" class="w-6 h-6" />
</RangeCalendarPrev>
<RangeCalendarHeading class="text-[15px] text-black font-medium" />
<RangeCalendarNext
class="inline-flex items-center cursor-pointer justify-center text-black rounded-[9px] bg-transparent w-8 h-8 hover:bg-black hover:text-white active:scale-98 active:transition-all focus:shadow-[0_0_0_2px] focus:shadow-black"
>
<Icon icon="radix-icons:chevron-right" class="w-6 h-6" />
</RangeCalendarNext>
</RangeCalendarHeader>
<div
class="flex flex-col space-y-4 pt-4 sm:flex-row sm:space-x-4 sm:space-y-0"
>
<RangeCalendarGrid v-for="month in grid" :key="month.value.toString()" class="w-full border-collapse select-none space-y-1">
<RangeCalendarGridHead>
<RangeCalendarGridRow class="mb-1 grid w-full grid-cols-7">
<RangeCalendarHeadCell
v-for="day in weekDays" :key="day"
class="rounded-md text-xs text-green8"
>
{{ day }}
</RangeCalendarHeadCell>
</RangeCalendarGridRow>
</RangeCalendarGridHead>
<RangeCalendarGridBody class="grid">
<RangeCalendarGridRow v-for="(weekDates, index) in month.rows" :key="`weekDate-${index}`" class="grid grid-cols-7">
<RangeCalendarCell
v-for="weekDate in weekDates"
:key="weekDate.toString()"
:date="weekDate"
>
<RangeCalendarCellTrigger
:day="weekDate"
:month="month.value"
class="relative flex items-center justify-center rounded-full whitespace-nowrap text-sm font-normal text-black w-8 h-8 outline-none focus:shadow-[0_0_0_2px] focus:shadow-black data-[disabled]:text-black/30 data-[selected]:!bg-green10 data-[selected]:text-white hover:bg-green5 data-[highlighted]:bg-green5 data-[unavailable]:pointer-events-none data-[unavailable]:text-black/30 data-[unavailable]:line-through before:absolute before:top-[5px] before:hidden before:rounded-full before:w-1 before:h-1 before:bg-white data-[today]:before:block data-[today]:before:bg-green9 "
/>
</RangeCalendarCell>
</RangeCalendarGridRow>
</RangeCalendarGridBody>
</RangeCalendarGrid>
</div>
</RangeCalendarRoot>
</template>
Credit
This component was built taking inspiration from the implementation in melt-ui.
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 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.
npm install -D @internationalized/date
Install the component from your command line.
npm install radix-vue
Anatomy
Import all parts and piece them together.
<script setup>
import {
RangeCalendarCell,
RangeCalendarCellTrigger,
RangeCalendarGrid,
RangeCalendarGridBody,
RangeCalendarGridHead,
RangeCalendarGridRow,
RangeCalendarHeadCell,
RangeCalendarHeader,
RangeCalendarHeading,
RangeCalendarNext,
RangeCalendarPrev,
RangeCalendarRoot
} from 'radix-vue'
</script>
<template>
<RangeCalendarRoot>
<RangeCalendarHeader>
<RangeCalendarPrev />
<RangeCalendarHeading />
<RangeCalendarNext />
</RangeCalendarHeader>
<RangeCalendarGrid>
<RangeCalendarGridHead>
<RangeCalendarGridRow>
<RangeCalendarHeadCell />
</RangeCalendarGridRow>
</RangeCalendarGridHead>
<RangeCalendarGridBody>
<RangeCalendarGridRow>
<RangeCalendarCell>
<RangeCalendarCellTrigger />
</RangeCalendarCell>
</RangeCalendarGridRow>
</RangeCalendarGridBody>
</RangeCalendarGrid>
</RangeCalendarRoot>
</template>
API Reference
Root
Contains all the parts of a calendar
Prop | Default | Type |
---|---|---|
as | 'div' | AsTag | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. | |
calendarLabel | string The accessible label for the calendar | |
defaultPlaceholder | DateValue The default placeholder date | |
defaultValue | { start: DateValue; end: DateValue; } The default value for the calendar | |
disabled | false | boolean Whether or not the calendar is disabled |
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 | 'en' | 'tr' | 'th' | 'en' | 'ach' | 'af' | 'am' | 'an' | 'ar' | 'ast' | 'az' | 'be' | 'bg' | 'bn' | 'br' | 'bs' | 'ca' | 'cak' | 'ckb' | 'cs' | 'cy' | 'da' | 'de' | 'dsb' | 'el' | 'eo' | 'es' | ... 49 more ... 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 | { start: DateValue; end: DateValue; } The controlled checked state of the calendar. Can be bound as | |
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. This updates as the user navigates the calendar and can be used to programatically control the calendar view | |
preventDeselect | false | boolean Whether or not to prevent the user from deselecting a date without selecting another date first |
readonly | false | boolean Whether or not 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 | 0 | 1 | 2 | 3 | 4 | 5 | 6 The day of the week to start the calendar on |
Emit | Payload |
---|---|
update:modelValue | [{ start: DateValue; end: DateValue; }] Event handler called whenever the model value changes |
update:placeholder | [date: DateValue] Event handler called whenever the placeholder value changes |
Slots (default) | Payload |
---|---|
date | DateValue The current date of the placeholder |
grid | Grid<DateValue>[] The grid of dates |
weekDays | string[] The days of the week |
formatter | Formatter The formatter used inside the calendar for displaying dates |
getMonths | DateValue The months that can be selected |
getYears |
The years that can be selected |
Header
Contains the navigation buttons and the heading segments.
Prop | Default | Type |
---|---|---|
as | 'div' | AsTag | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Prev Button
Calendar navigation button. It navigates the calendar one month/year/decade in the past based on the current calendar view.
Prop | Default | Type |
---|---|---|
as | 'button' | AsTag | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
NextButton
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' | AsTag | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Heading
Heading for displaying the current month and year.
Prop | Default | Type |
---|---|---|
as | 'div' | AsTag | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Slots (default) | Payload |
---|---|
headingValue | string Current month and year |
Grid
Container for wrapping the calendar grid.
Prop | Default | Type |
---|---|---|
as | 'table' | AsTag | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Grid Head
Container for wrapping the grid head.
Prop | Default | Type |
---|---|---|
as | 'thead' | AsTag | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Grid Body
Container for wrapping the grid body.
Prop | Default | Type |
---|---|---|
as | 'tbody' | AsTag | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Grid Row
Container for wrapping the grid row.
Prop | Default | Type |
---|---|---|
as | 'tr' | AsTag | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Head Cell
Container for wrapping the head cell. Used for displaying the week days.
Prop | Default | Type |
---|---|---|
as | 'th' | AsTag | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change the default rendered element for the one passed as a child, merging their props and behavior. Read our Composition guide for more details. |
Cell
Container for wrapping the calendar cells.
Prop | Default | Type |
---|---|---|
as | 'td' | AsTag | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change 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 |
Cell Trigger
Interactable container for displaying the cell dates. Clicking it selects the date.
Prop | Default | Type |
---|---|---|
as | 'div' | AsTag | Component The element or component this component should render as. Can be overwrite by |
asChild | boolean Change 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 |
Accessibility
Keyboard Interactions
Key | Description |
---|---|
Tab | When focus moves onto the calendar, focuses the first navigation button. |
Space |
When the focus is on either CalendarNext or CalendarPrev , it navigates the calendar. Otherwise, it selects the date.
|
Enter |
When the focus is on either CalendarNext or CalendarPrev , it navigates the calendar. Otherwise, it selects the date.
|
ArrowLeftArrowRightArrowUpArrowDown |
When the focus is on CalendarCellTrigger , it navigates the dates, changing the month/year/decade if necessary.
|