Skip to content

Range Calendar

Alpha
Presents a calendar view tailored for selecting date ranges.
Event Date, March 2024
March 2024
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
vue
<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.

bash
npm install -D @internationalized/date

Install the component from your command line.

bash
npm install radix-vue

Anatomy

Import all parts and piece them together.

vue
<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

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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 v-model.

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

EmitPayload
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

Contains the navigation buttons and the heading segments.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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.

PropDefaultType
as
'button'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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.

PropDefaultType
as
'button'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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.

PropDefaultType
as
'table'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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.

PropDefaultType
as
'thead'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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.

PropDefaultType
as
'tbody'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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.

PropDefaultType
as
'tr'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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.

PropDefaultType
as
'th'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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.

PropDefaultType
as
'td'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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.

PropDefaultType
as
'div'
AsTag | Component

The element or component this component should render as. Can be overwrite by asChild

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
Slots (default)Payload
text
string

Accessibility

Keyboard Interactions

KeyDescription
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.