Docs
Calendar

Calendar

A date field component that allows users to enter and edit date.

Needs work: The below is a basic example. I am still working on ensuring this is feature complete.

November 2023

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

Installation

Install the following dependencies:

npm install @internationalized/date date-fns

Add the Button component to your project.

The Calendar component uses the Button component. Make sure you have it installed in your project.

Copy and paste the following code into your project.

"use client"
 
import * as React from "react"
import { getLocalTimeZone, today } from "@internationalized/date"
import { ChevronLeft, ChevronRight } from "lucide-react"
import {
  Button,
  Calendar,
  CalendarCell,
  CalendarCellProps,
  CalendarGrid,
  CalendarGridBody,
  CalendarGridBodyProps,
  CalendarGridHeader,
  CalendarGridHeaderProps,
  CalendarGridProps,
  CalendarHeaderCell,
  CalendarHeaderCellProps,
  Heading,
} from "react-aria-components"
 
import { cn, cnv } from "@/lib/utils"
import { buttonVariants } from "@/components/ui/button-variants"
 
const _Calendar = Calendar
 
const _CalendarHeading = ({
  ...props
}: React.HTMLAttributes<HTMLHeadElement>) => (
  <header className="relative flex items-center justify-center pt-1" {...props}>
    <Heading className="text-sm font-medium" />
    <div className="flex items-center">
      <Button
        slot="next"
        className={cn(
          buttonVariants({ variant: "outline" }),
          "h-7 w-7 bg-transparent p-0 opacity-50 data-[hovered]:opacity-100",
          "absolute right-1 text-popover-foreground"
        )}
      >
        <ChevronRight className="h-4 w-4" />
      </Button>
      <Button
        slot="previous"
        className={cn(
          buttonVariants({ variant: "outline" }),
          "h-7 w-7 bg-transparent p-0 opacity-50 data-[hovered]:opacity-100",
          "absolute left-1 text-popover-foreground"
        )}
      >
        <ChevronLeft className="h-4 w-4" />
      </Button>
    </div>
  </header>
)
 
const _CalendarGrid = ({ className, ...props }: CalendarGridProps) => (
  <CalendarGrid
    className={cn("mt-4 w-full border-collapse space-y-1", className)}
    {...props}
  />
)
 
const _CalendarGridHeader = ({
  className,
  ...props
}: CalendarGridHeaderProps) => (
  <CalendarGridHeader className={cn("[&>tr]:flex", className)} {...props} />
)
 
const _CalendarHeaderCell = ({
  className,
  ...props
}: CalendarHeaderCellProps) => (
  <CalendarHeaderCell
    className={cn(
      "w-9 rounded-md text-[0.8rem] font-normal text-muted-foreground",
      className
    )}
    {...props}
  />
)
 
const _CalendarGridBody = ({ className, ...props }: CalendarGridBodyProps) => (
  <CalendarGridBody
    className={cn(
      "[&>tr>td]:p-0 [&>tr]:mt-2 [&>tr]:flex [&>tr]:w-full",
      className
    )}
    {...props}
  />
)
 
;("outline-none ring-2 ring-ring ring-offset-2")
 
const _CalendarCell = ({ className, date, ...props }: CalendarCellProps) => (
  <CalendarCell
    className={(values) =>
      cnv(
        values,
        "h-9 w-9 p-0 font-normal data-[selected]:opacity-100 inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm ring-offset-background transition-colors data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[hovered]:bg-accent data-[hovered]:text-accent-foreground",
        date.compare(today(getLocalTimeZone())) === 0 &&
          "bg-accent text-accent-foreground",
        values.isDisabled && "text-muted-foreground opacity-50",
        values.isFocusVisible &&
          values.isFocused &&
          "outline-none ring-2 ring-ring ring-offset-2",
        values.isSelected &&
          "bg-primary text-primary-foreground data-[hovered]:bg-primary data-[hovered]:text-primary-foreground data-[focused]:bg-primary data-[focused]:text-primary-foreground",
        values.isOutsideMonth &&
          "text-muted-foreground opacity-50 data-[selected]:bg-accent/50 data-[selected]:text-muted-foreground data-[selected]:opacity-30",
 
        className
      )
    }
    date={date}
    {...props}
  />
)
 
export {
  _Calendar as Calendar,
  _CalendarCell as CalendarCell,
  _CalendarGrid as CalendarGrid,
  _CalendarGridBody as CalendarGridBody,
  _CalendarGridHeader as CalendarGridHeader,
  _CalendarHeaderCell as CalendarHeaderCell,
  _CalendarHeading as CalendarHeading,
}

Update the import paths to match your project setup.

Usage

import {
  Calendar,
  CalendarCell,
  CalendarGrid,
  CalendarGridBody,
  CalendarGridHeader,
  CalendarHeaderCell,
  CalendarHeading,
} from "@/registry/default/ui/calendar"
 
return (
  <Calendar>
    <CalendarHeading />
    <CalendarGrid>
      <CalendarGridHeader>
        {(day) => <CalendarHeaderCell>{day}</CalendarHeaderCell>}
      </CalendarGridHeader>
      <CalendarGridBody>
        {(date) => (
          <>
            <CalendarCell date={date} />
          </>
        )}
      </CalendarGridBody>
    </CalendarGrid>
  </Calendar>
)

Date Picker

You can use the <Calendar> component to build a date picker. See the Date Picker page for more information.