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
S | M | T | W | T | F | S |
---|---|---|---|---|---|---|
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.