Shadcn Calendar for React and Tailwind
Select a date, dates, or a range from an inline calendar.
| S | M | T | W | T | F | S |
|---|---|---|---|---|---|---|
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 | 3 |
Installation
bunx --bun shadcn@latest add https://kit.dev/r/calendar.jsonpnpm dlx shadcn@latest add https://kit.dev/r/calendar.jsonnpx shadcn@latest add https://kit.dev/r/calendar.jsonyarn shadcn@latest add https://kit.dev/r/calendar.json<Step>This component depends on Button and Native Select. Install them first if you haven't already.</Step>
Install the following dependencies:
bun add @ark-ui/react lucide-reactpnpm add @ark-ui/react lucide-reactnpm install @ark-ui/react lucide-reactyarn add @ark-ui/react lucide-reactCopy and paste the following code into your project.
"use client";
import {
DatePicker as ArkCalendar,
useDatePicker as useArkDatePicker,
useDatePickerContext as useArkDatePickerContext,
} from "@ark-ui/react/date-picker";
import {
ChevronDownIcon,
ChevronLeftIcon,
ChevronRightIcon,
} from "lucide-react";
import type React from "react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import { nativeSelectVariants } from "@/components/ui/native-select";
export const useCalendar = useArkDatePicker;
export const useCalendarContext = useArkDatePickerContext;
export const CalendarContext: typeof ArkCalendar.Context = ArkCalendar.Context;
const calendarRootClassName = cn("[--cell-size:--spacing(9)]", "w-fit");
export const Calendar = (
props: React.ComponentProps<typeof ArkCalendar.Root>
) => {
const { lazyMount = true, unmountOnExit = true, className, ...rest } = props;
return (
<ArkCalendar.Root
className={cn(calendarRootClassName, className)}
data-slot="calendar"
inline
lazyMount={lazyMount}
unmountOnExit={unmountOnExit}
{...rest}
/>
);
};
export const CalendarRootProvider = (
props: React.ComponentProps<typeof ArkCalendar.RootProvider>
) => {
const { lazyMount = true, unmountOnExit = true, className, ...rest } = props;
return (
<ArkCalendar.RootProvider
className={cn(calendarRootClassName, className)}
data-slot="calendar"
lazyMount={lazyMount}
unmountOnExit={unmountOnExit}
{...rest}
/>
);
};
export const CalendarControl = (
props: React.ComponentProps<typeof ArkCalendar.Control>
) => (
<ArkCalendar.Control
className="inline-flex items-center gap-2"
data-slot="calendar-control"
{...props}
/>
);
export const CalendarLabel = (
props: React.ComponentProps<typeof ArkCalendar.Label>
) => (
<ArkCalendar.Label
className="font-medium text-sm"
data-slot="calendar-label"
{...props}
/>
);
export const CalendarTrigger = (
props: React.ComponentProps<typeof ArkCalendar.Trigger>
) => <ArkCalendar.Trigger data-slot="calendar-trigger" {...props} />;
export const CalendarPresetTrigger = (
props: React.ComponentProps<typeof ArkCalendar.PresetTrigger>
) => (
<ArkCalendar.PresetTrigger data-slot="calendar-preset-trigger" {...props} />
);
export const CalendarViewDate = (
props: React.ComponentProps<typeof ArkCalendar.RangeText>
) => {
const { className, ...rest } = props;
return (
<ArkCalendar.RangeText
className={cn("font-medium text-sm", className)}
data-slot="calendar-range-text"
{...rest}
/>
);
};
export const CalendarTodayTrigger = (
props: React.ComponentProps<typeof Button>
) => {
const { variant = "outline", size = "lg", ...rest } = props;
return (
<CalendarContext>
{(calendar) => {
const handleSelectToday = () => {
calendar.selectToday();
};
return (
<Button
data-slot="calendar-today-trigger"
onClick={handleSelectToday}
size={size}
variant={variant}
{...rest}
>
Today
</Button>
);
}}
</CalendarContext>
);
};
export const CalendarClearTrigger = (
props: React.ComponentProps<typeof ArkCalendar.ClearTrigger>
) => <ArkCalendar.ClearTrigger data-slot="calendar-clear-trigger" {...props} />;
export const CalendarYearSelect = (
props: React.ComponentProps<typeof ArkCalendar.YearSelect>
) => {
const { className, ...rest } = props;
return (
<div
className={cn("relative w-fit has-[select:disabled]:opacity-64")}
data-slot="calendar-year-select-wrapper"
>
<ArkCalendar.YearSelect
className={cn(nativeSelectVariants())}
data-slot="calendar-year-select"
{...rest}
/>
<ChevronDownIcon
aria-hidden="true"
className={cn(
"absolute inset-e-2.5 top-1/2 -translate-y-1/2",
"size-4",
"select-none text-muted-foreground",
"pointer-events-none"
)}
data-slot="calendar-year-select-icon"
/>
</div>
);
};
export const CalendarMonthSelect = (
props: React.ComponentProps<typeof ArkCalendar.MonthSelect>
) => {
const { className, ...rest } = props;
return (
<div
className={cn("relative w-fit has-[select:disabled]:opacity-64")}
data-slot="calendar-month-select-wrapper"
>
<ArkCalendar.MonthSelect
className={cn(nativeSelectVariants(), className)}
data-slot="calendar-month-select"
{...rest}
/>
<ChevronDownIcon
aria-hidden="true"
className={cn(
"absolute inset-e-2.5 top-1/2 -translate-y-1/2",
"size-4",
"select-none text-muted-foreground",
"pointer-events-none"
)}
data-slot="calendar-month-select-icon"
/>
</div>
);
};
export const CalendarView = (
props: React.ComponentProps<typeof ArkCalendar.View>
) => {
const { className, ...rest } = props;
return (
<ArkCalendar.View
className={cn("flex flex-col gap-1", className)}
data-slot="calendar-view"
{...rest}
/>
);
};
export const CalendarViewTrigger = (
props: React.ComponentProps<typeof ArkCalendar.ViewTrigger>
) => {
const { className, children, ...rest } = props;
return (
<ArkCalendar.ViewTrigger
className={cn(
"rounded-md px-2 py-1",
"font-medium text-sm",
"outline-none hover:bg-accent",
"focus-visible:border-primary focus-visible:ring-[3px] focus-visible:ring-ring/32",
className
)}
data-slot="calendar-view-trigger"
{...rest}
>
{children ?? <CalendarViewDate />}
</ArkCalendar.ViewTrigger>
);
};
export const CalendarViewControl = (
props: React.ComponentProps<typeof ArkCalendar.ViewControl>
) => {
const { className, ...rest } = props;
return (
<ArkCalendar.ViewControl
className={cn(
"relative",
"h-auto w-full",
"flex items-center gap-1.5",
className
)}
data-slot="calendar-view-control"
{...rest}
/>
);
};
export const CalendarPrevTrigger = (
props: React.ComponentProps<typeof ArkCalendar.PrevTrigger>
) => (
<ArkCalendar.PrevTrigger asChild data-slot="calendar-prev-trigger" {...props}>
<Button
aria-label="Previous"
className="me-auto"
size="icon-md"
variant="ghost"
>
<ChevronLeftIcon aria-hidden className="rtl:rotate-180" />
</Button>
</ArkCalendar.PrevTrigger>
);
export const CalendarNextTrigger = (
props: React.ComponentProps<typeof ArkCalendar.NextTrigger>
) => (
<ArkCalendar.NextTrigger asChild data-slot="calendar-next-trigger" {...props}>
<Button
aria-label="Next"
className="ms-auto"
size="icon-md"
variant="ghost"
>
<ChevronRightIcon aria-hidden className="rtl:rotate-180" />
</Button>
</ArkCalendar.NextTrigger>
);
export const CalendarTable = (
props: React.ComponentProps<typeof ArkCalendar.Table>
) => {
const { className, ...rest } = props;
return (
<ArkCalendar.Table
className={cn("group", "w-full min-w-60", "border-collapse", className)}
data-slot="calendar-table"
{...rest}
/>
);
};
interface CalendarWeekDaysProps
extends React.ComponentProps<typeof ArkCalendar.TableHead> {
/**
* The format of the week days
*
* @default 'narrow'
*/
format?: "narrow" | "short" | "long";
}
export const CalendarWeekDays = (props: CalendarWeekDaysProps) => {
const { format = "narrow", ...rest } = props;
return (
<CalendarContext>
{(calendar) => (
<CalendarTableHead data-slot="calendar-table-head" {...rest}>
<CalendarTableRow>
{calendar.showWeekNumbers ? (
<CalendarWeekNumberHeaderCell>Wk</CalendarWeekNumberHeaderCell>
) : null}
{calendar.weekDays.map((weekDay) => (
<CalendarTableHeader key={weekDay.short}>
{weekDay[format]}
</CalendarTableHeader>
))}
</CalendarTableRow>
</CalendarTableHead>
)}
</CalendarContext>
);
};
export const CalendarTableDays = (
props: React.ComponentProps<typeof CalendarTableBody>
) => {
const { tabIndex, ...rest } = props;
return (
<CalendarContext>
{(calendar) => (
<CalendarTableBody {...rest}>
{calendar.weeks.map((week, index) => (
<CalendarTableRow key={week.map((day) => day.toString()).join("-")}>
{calendar.showWeekNumbers ? (
<CalendarWeekNumberCell week={week} weekIndex={index}>
{calendar.getWeekNumber(week)}
</CalendarWeekNumberCell>
) : null}
{week.map((day) => (
<CalendarTableCell
key={day.toString()}
tabIndex={tabIndex ?? undefined}
value={day}
>
{day.day}
</CalendarTableCell>
))}
</CalendarTableRow>
))}
</CalendarTableBody>
)}
</CalendarContext>
);
};
interface CalendarTableNextMonthProps
extends React.ComponentProps<typeof CalendarTableBody> {
/**
* The number of months to offset
*
* @default 1
*/
months?: number;
}
export const CalendarTableNextMonth = (props: CalendarTableNextMonthProps) => {
const { months = 1, tabIndex, ...rest } = props;
return (
<CalendarContext>
{(calendar) => {
const offset = calendar.getOffset({ months });
return (
<CalendarTableBody {...rest}>
{offset.weeks.map((week) => (
<CalendarTableRow
key={week.map((day) => day.toString()).join("-")}
>
{week.map((day) => (
<CalendarTableCell
key={day.toString()}
tabIndex={tabIndex ?? undefined}
value={day}
visibleRange={offset.visibleRange}
>
{day.day}
</CalendarTableCell>
))}
</CalendarTableRow>
))}
</CalendarTableBody>
);
}}
</CalendarContext>
);
};
export const CalendarTableHead = (
props: React.ComponentProps<typeof ArkCalendar.TableHead>
) => <ArkCalendar.TableHead data-slot="calendar-table-head" {...props} />;
export const CalendarTableRow = (
props: React.ComponentProps<typeof ArkCalendar.TableRow>
) => {
const { className, ...rest } = props;
return (
<ArkCalendar.TableRow
className={cn("mt-1 flex w-full", className)}
data-slot="calendar-table-row"
{...rest}
/>
);
};
export const CalendarTableHeader = (
props: React.ComponentProps<typeof ArkCalendar.TableHeader>
) => {
const { className, ...rest } = props;
return (
<ArkCalendar.TableHeader
className={cn(
"h-(--cell-size) w-full",
"flex items-center justify-center",
"select-none font-medium text-muted-foreground/64 text-xs",
"rounded-lg",
className
)}
data-slot="calendar-table-header"
{...rest}
/>
);
};
export const CalendarTableBody = (
props: React.ComponentProps<typeof ArkCalendar.TableBody>
) => <ArkCalendar.TableBody data-slot="calendar-table-body" {...props} />;
export const CalendarTableCell = (
props: React.ComponentProps<typeof ArkCalendar.TableCell>
) => {
const { value, visibleRange, className, ...rest } = props;
return (
<ArkCalendar.TableCell
className={cn(
"relative",
"h-(--cell-size) w-full",
"select-none text-center",
"[&:first-child[aria-selected=true]_div]:rounded-s-lg",
"[&:last-child[aria-selected=true]_div]:rounded-e-lg"
)}
data-slot="calendar-table-cell"
value={value}
visibleRange={visibleRange}
>
<ArkCalendar.TableCellTrigger
className={cn(
"inline-flex items-center justify-center gap-1",
"h-(--cell-size) w-full min-w-(--cell-size) data-[view=day]:h-(--cell-size)",
"select-none whitespace-nowrap font-normal text-base text-foreground leading-none sm:text-sm",
"rounded-lg border border-transparent",
"hover:bg-accent hover:text-accent-foreground",
"data-today:data-selected:after:bg-background data-today:after:absolute data-today:after:start-1/2 data-today:after:bottom-1 data-today:after:size-1 data-today:after:-translate-x-1/2 data-today:after:rounded-full data-today:after:bg-primary",
"data-focus:border-primary data-focus:bg-accent/30 data-focus:text-primary data-focus:ring-[3px] data-focus:ring-ring/32",
"outline-none focus-visible:border-primary focus-visible:ring-[3px] focus-visible:ring-ring/32",
"data-disabled:pointer-events-none data-disabled:opacity-64",
"data-unavailable:pointer-events-none data-unavailable:line-through data-unavailable:opacity-64",
"data-[view=day]:data-in-range:rounded-none data-[view=day]:data-in-range:not-[data-selected]:bg-primary/10",
"data-selected:bg-primary! data-selected:text-primary-foreground!",
"data-hover-range-start:rounded-s-lg! data-range-start:rounded-s-lg!",
"data-hover-range-end:rounded-e-lg! data-range-end:rounded-e-lg!",
"[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0",
className
)}
data-slot="calendar-table-cell-trigger"
{...rest}
/>
</ArkCalendar.TableCell>
);
};
export const CalendarWeekNumberHeaderCell = (
props: React.ComponentProps<typeof ArkCalendar.WeekNumberHeaderCell>
) => {
const { className, ...rest } = props;
return (
<ArkCalendar.WeekNumberHeaderCell
className={cn(
"h-(--cell-size) w-full min-w-(--cell-size)",
"flex items-center justify-center",
"select-none font-medium text-muted-foreground/64 text-xs",
className
)}
data-slot="calendar-week-number-header-cell"
{...rest}
/>
);
};
export const CalendarWeekNumberCell = (
props: React.ComponentProps<typeof ArkCalendar.WeekNumberCell>
) => {
const { className, ...rest } = props;
return (
<ArkCalendar.WeekNumberCell
className={cn(
"h-(--cell-size) w-full min-w-(--cell-size)",
"flex items-center justify-center",
"select-none text-muted-foreground text-xs",
className
)}
data-slot="calendar-week-number-cell"
{...rest}
/>
);
};
interface CalendarTableMonthsProps
extends React.ComponentProps<typeof CalendarTableBody> {
columns?: number;
format?: "short" | "long";
}
export const CalendarTableMonths = (props: CalendarTableMonthsProps) => {
const { columns = 4, format = "short", ...rest } = props;
return (
<CalendarContext>
{(calendar) => (
<CalendarTableBody {...rest}>
{calendar.getMonthsGrid({ columns, format }).map((months) => (
<CalendarTableRow
key={months.map((month) => month.value).join("-")}
>
{months.map((month) => (
<CalendarTableCell key={month.value} value={month.value}>
{month.label}
</CalendarTableCell>
))}
</CalendarTableRow>
))}
</CalendarTableBody>
)}
</CalendarContext>
);
};
interface CalendarTableYearsProps
extends React.ComponentProps<typeof CalendarTableBody> {
columns?: number;
}
export const CalendarTableYears = (props: CalendarTableYearsProps) => {
const { columns = 4, ...rest } = props;
return (
<CalendarContext>
{(calendar) => (
<CalendarTableBody {...rest}>
{calendar.getYearsGrid({ columns }).map((years) => (
<CalendarTableRow key={years.map((year) => year.value).join("-")}>
{years.map((year) => (
<CalendarTableCell key={year.value} value={year.value}>
{year.label}
</CalendarTableCell>
))}
</CalendarTableRow>
))}
</CalendarTableBody>
)}
</CalendarContext>
);
};Update the import paths to match your project setup.
Anatomy
Calendar is Ark Date Picker with inline. For a popup field, use Date Picker.
Calendar
├── CalendarViewControl
│ ├── CalendarPrevTrigger
│ ├── CalendarViewDate | CalendarViewTrigger
│ ├── CalendarMonthSelect
│ ├── CalendarYearSelect
│ └── CalendarNextTrigger
└── CalendarTable
├── CalendarWeekDays
└── CalendarTableDays | CalendarTableMonths | CalendarTableYears | CalendarTableNextMonthWrap a view in CalendarView when you render day, month, and year grids together.
Usage
import {
Calendar,
CalendarNextTrigger,
CalendarPrevTrigger,
CalendarTable,
CalendarTableDays,
CalendarViewControl,
CalendarViewDate,
CalendarWeekDays,
} from "@/components/ui/calendar";<Calendar>
<CalendarViewControl>
<CalendarPrevTrigger />
<CalendarViewDate />
<CalendarNextTrigger />
</CalendarViewControl>
<CalendarTable>
<CalendarWeekDays />
<CalendarTableDays />
</CalendarTable>
</Calendar>Values are DateValue[] from @internationalized/date. Use parseDate to build them.
Controlled
Use value and onValueChange.
Root Provider
Use useCalendar with CalendarRootProvider when you need the API outside the tree. Pass inline: true (and other machine options) to useCalendar(), not to the provider.
Examples
Default value
Date range
Set selectionMode="range".
Multiple dates
Set selectionMode="multiple".
Max selected dates
Limit multiple selection with maxSelectedDates.
Month and year selector
Default view
Open on the month grid. Click the header to move between day, month, and year.
Month picker
defaultView="month" and minView="month".
Year picker
defaultView="year" and minView="year".
Month range
Year range
Multiple months
Set numOfMonths and render CalendarTableNextMonth for the offset month.
Presets
CalendarPresetTrigger with values such as last7Days, last30Days, thisMonth.
Min and max
Unavailable dates
isDateUnavailable disables matching days (weekends here).
Select today
Fixed weeks
Always render 6 weeks so the height does not jump between months.
Week numbers
Set showWeekNumbers. CalendarWeekDays and CalendarTableDays add the week column.
Locale
locale and startOfWeek (0 = Sunday, 1 = Monday, …).
Custom cell size
Use [--cell-size:--spacing(n)]. Default is --spacing(9).
md:[--cell-size:--spacing(10)] lg:[--cell-size:--spacing(12)]Guides
Date Picker
Calendar is always inline. Use Date Picker when you need an input, trigger, and popup.
parseDate
import { parseDate } from "@ark-ui/react/date-picker";
<Calendar defaultValue={[parseDate("2025-01-15")]} />Multiple months
<Calendar numOfMonths={2} selectionMode="range">
<CalendarTable>
<CalendarWeekDays />
<CalendarTableDays />
</CalendarTable>
<CalendarTable>
<CalendarWeekDays />
<CalendarTableNextMonth months={1} />
</CalendarTable>
</Calendar>API Reference
shadcn.io wraps Ark UI Date Picker with inline. Defaults below are shadcn.io values. lazyMount and unmountOnExit default to true (Ark: false). inline is true unless you override it.
asChild merges props onto a single child element.
Calendar
Root. Renders a div.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Render the child element instead of a div. |
className | string | - | Class names on the root. Set [--cell-size:] here. |
closeOnSelect | boolean | true | Close after selection. Ignored for multiple. Little effect when inline. |
createCalendar | (identifier: CalendarIdentifier) => Calendar | - | Non-Gregorian calendars. |
defaultFocusedValue | DateValue | - | Uncontrolled focused date. |
defaultOpen | boolean | - | Uncontrolled open state. |
defaultValue | DateValue[] | - | Uncontrolled selected dates. |
defaultView | "day" | "month" | "year" | "day" | Initial view. |
disabled | boolean | - | Disable the calendar. |
fixedWeeks | boolean | - | Always show 6 weeks in the day view. |
focusedValue | DateValue | - | Controlled focused date. |
format | (date: DateValue, details: LocaleDetails) => string | - | Format for inputs (Date Picker). |
hideMode | "display-none" | "activity" | "display-none" | How to hide inactive views. activity needs React 19+. |
id | string | - | Unique id for the machine. |
ids | object | - | Element ids for composition. |
inline | boolean | true | Render on the page, not in a popup. |
invalid | boolean | - | Mark as invalid. |
isDateUnavailable | (date: DateValue, locale: string) => boolean | - | Disable matching dates. |
lazyMount | boolean | true | Mount views on first use. |
locale | string | "en-US" | BCP 47 locale. |
max | DateValue | - | Latest selectable date. |
maxSelectedDates | number | - | Cap for selectionMode="multiple". |
maxView | "day" | "month" | "year" | "year" | Highest view. |
min | DateValue | - | Earliest selectable date. |
minView | "day" | "month" | "year" | "day" | Lowest view. |
name | string | - | Native input name (Date Picker). |
numOfMonths | number | - | Months to display. Use with CalendarTableNextMonth. |
onFocusChange | (details: FocusChangeDetails) => void | - | Focused date changed. |
onOpenChange | (details: OpenChangeDetails) => void | - | Open state changed. |
onValueChange | (details: ValueChangeDetails) => void | - | Selection changed. { value: DateValue[] }. |
onViewChange | (details: ViewChangeDetails) => void | - | View changed. |
onVisibleRangeChange | (details: VisibleRangeChangeDetails) => void | - | Visible month range changed. |
open | boolean | - | Controlled open state. |
openOnClick | boolean | false | Open on input click (Date Picker). |
outsideDaySelectable | boolean | false | Allow days outside the visible month. |
parse | (value: string, details: LocaleDetails) => DateValue | undefined | - | Parse input text (Date Picker). |
placeholder | string | - | Input placeholder (Date Picker). |
positioning | PositioningOptions | - | Popup position (Date Picker). |
readOnly | boolean | - | Non-editable. |
required | boolean | - | Required for forms. |
selectionMode | "single" | "multiple" | "range" | "single" | How many dates can be selected. |
showWeekNumbers | boolean | - | ISO week column in the day view. |
startOfWeek | number | - | 0 Sunday … 6 Saturday. |
timeZone | string | "UTC" | Time zone. |
translations | Partial<IntlTranslations> | - | Localized strings. |
unmountOnExit | boolean | true | Unmount inactive views. |
value | DateValue[] | - | Controlled selected dates. |
view | "day" | "month" | "year" | - | Controlled view. |
| Attribute | Description |
|---|---|
data-slot | calendar |
data-scope | date-picker |
data-part | root |
data-state | "open" or "closed" |
data-disabled | Present when disabled |
data-readonly | Present when read-only |
| CSS variable | Default | Description |
|---|---|---|
--cell-size | --spacing(9) | Width/height of day cells |
CalendarRootProvider
Takes the API from useCalendar. Pass inline: true to useCalendar().
| Prop | Type | Default | Description |
|---|---|---|---|
value | UseDatePickerReturn | required | Return value of useCalendar(). |
asChild | boolean | false | Render the child element instead of a div. |
className | string | - | Class names on the root. |
lazyMount | boolean | true | Mount views on first use. |
unmountOnExit | boolean | true | Unmount inactive views. |
CalendarViewControl
Header row for prev/next and the month label or selects.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Merge onto a single child. |
className | string | - | Class names on the control. |
| Attribute | Description |
|---|---|
data-slot | calendar-view-control |
data-part | view-control |
data-view | "day", "month", or "year" |
CalendarPrevTrigger / CalendarNextTrigger
Navigate the visible range. Render as Button size="icon-md" variant="ghost" with aria-label "Previous" / "Next". Chevrons flip in RTL.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | true | Merged onto the inner Button. |
className | string | - | Class names on the trigger. |
CalendarViewDate
Visible month/year label (RangeText).
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Merge onto a single child. |
className | string | - | Class names on the label. |
CalendarViewTrigger
Button that changes view (day → month → year). Defaults to rendering CalendarViewDate.
CalendarView
One calendar view.
| Prop | Type | Default | Description |
|---|---|---|---|
view | "day" | "month" | "year" | - | Which grid this block is. |
asChild | boolean | false | Merge onto a single child. |
className | string | - | Class names on the view. |
CalendarMonthSelect / CalendarYearSelect
Native <select> dropdowns. Year/month select wrap a chevron. CalendarMonthSelect accepts Ark’s month format options.
CalendarTable
Day/month/year grid. Renders a table.
| Prop | Type | Default | Description |
|---|---|---|---|
columns | number | - | Column count for month/year grids. |
asChild | boolean | false | Merge onto a single child. |
className | string | - | Class names on the table. |
CalendarWeekDays
Header row. format: "narrow" (default), "short", "long". Adds a week-number header when showWeekNumbers is set.
CalendarTableDays
Day cells for the focused month. Adds week-number cells when showWeekNumbers is set.
CalendarTableNextMonth
Day cells offset by months (default 1) via getOffset.
CalendarTableMonths / CalendarTableYears
Month and year grids (getMonthsGrid / getYearsGrid). columns default 4.
CalendarTableCell
One selectable cell. value is a DateValue (day) or number (month/year).
| Prop | Type | Default | Description |
|---|---|---|---|
value | DateValue | number | required | Cell value. |
visibleRange | VisibleRange | - | Visible range for offset months. |
disabled | boolean | - | Disable the cell. |
className | string | - | Class names on the cell trigger. |
| Attribute | Description |
|---|---|
data-selected | Present when selected |
data-today | Present for today |
data-disabled | Present when disabled |
data-unavailable | Present when unavailable |
data-in-range | Present inside a range |
data-range-start / data-range-end | Range endpoints |
data-focus | Present when focused |
CalendarPresetTrigger
Quick range. value is a preset such as "last7Days", "last30Days", "thisMonth", "lastMonth", "thisWeek", "lastWeek". Use asChild with Button.
CalendarTodayTrigger
Button that calls selectToday() from context.
CalendarWeekNumberHeaderCell / CalendarWeekNumberCell
Week-number column. Prefer showWeekNumbers on the root with CalendarWeekDays / CalendarTableDays.
Other Date Picker parts
CalendarLabel, CalendarControl, CalendarTrigger, CalendarClearTrigger are still exported for popup/input composition. Prefer Date Picker for those layouts.
useCalendar
Creates the date-picker API for CalendarRootProvider.
const calendar = useCalendar({ inline: true });
calendar.selectToday();CalendarContext / useCalendarContext
Render-prop or hook access. Use inside Calendar or CalendarRootProvider.
| Property | Type | Description |
|---|---|---|
value | DateValue[] | Selected dates. |
valueAsString | string[] | Selected dates as strings. |
focusedValue | DateValue | Focused date. |
view | "day" | "month" | "year" | Current view. |
weeks | DateValue[][] | Weeks in the visible month. |
weekDays | WeekDay[] | Weekday labels. |
visibleRange | VisibleRange | Visible start/end. |
selectionMode | SelectionMode | single, multiple, or range. |
selectToday | () => void | Select today. |
setValue | (values: DateValue[]) => void | Set selection. |
clearValue | (options?: { focus?: boolean }) => void | Clear selection. |
setView | (view: DateView) => void | Change view. |
goToNext / goToPrev | () => void | Move the visible range. |
getOffset | (duration: DateDuration) => DateValueOffset | Data for an adjacent month. |
getMonthsGrid | (props?: MonthGridProps) => MonthGridValue | Month cells. |
getYearsGrid | (props?: YearGridProps) => YearGridValue | Year cells. |
getWeekNumber | (week: DateValue[]) => number | ISO week number. |
isUnavailable | (date: DateValue) => boolean | Whether a date is blocked. |
CalendarContext children: (context) => ReactNode.
Accessibility
Complies with the Date Picker WAI-ARIA pattern for the grid. Prev/next controls have aria-label. Decorative chevrons are aria-hidden.
Keyboard support
| Key | Description |
|---|---|
ArrowLeft | Previous day in the week (flips in RTL). |
ArrowRight | Next day in the week. |
ArrowUp | Same weekday in the previous week. |
ArrowDown | Same weekday in the next week. |
Home | First day of the month. |
End | Last day of the month. |
PageUp | Same day in the previous month. |
PageDown | Same day in the next month. |
Enter | Select the focused date. |
Esc | Close a popup Date Picker. No-op when inline. |