Calendar

Browse dates in a clear, compact month view.

pnpm dlx shadcn@latest add @uiarc/calendar
Live · keyboard ready
  • Inline date picking where the month should stay visible, such as booking pages.
  • Picking one date with blocked days via minDate, maxDate, and disabledDates.
  • Use date-picker for a form field that opens a calendar popover.
  • Use time-picker for times of day.
  • Use booking-pill for a full compact booking flow.

Installation

Add Calendar with the shadcn CLI, or copy the source by hand.

pnpm dlx shadcn@latest add @uiarc/calendar

Adds the component and its local dependencies, and installs motion, lucide-react. First time? Add the @uiarc registry to components.json, or use the full URL:

example.tsx
import { Calendar } from "@/registry/components/calendar/calendar"; export function DeliveryDate() {  const [date, setDate] = useState<Date>();  return (    <Calendar      value={date}      onChange={setDate}      minDate={new Date()}      disabledDates={(day) => day.getDay() === 0}      showToday    />  );}

API reference

2 parts. The first is the root.

Calendar

A month grid for picking one date, with sliding month changes and a gliding selection.

PropTypeDefaultDescription
valueDate–Selected date.
onChange(date: Date) => void–Called when a day is picked.
monthDate–Controlled visible month.
onMonthChange(month: Date) => void–Called with the first of the new month when navigating.
minDateDate–Earliest selectable day.
maxDateDate–Latest selectable day.
disabledDates(date: Date) => boolean–Return true to block a day, such as weekends.
localestring"en-US"Month, weekday, and day names.
classNamestring–Added to the root section.
showTodaybooleanfalseAdds a Today button that returns to the current month and selects today when allowed.

useToday

Hook returning the viewer's local date, undefined during SSR and hydration, and updating across midnight.

No props.

Arrow keys
Move by one day or one week, skipping blocked days and crossing months.
HomeorEnd
Move to the start or end of the week.
PageUporPageDown
Move by one month; with Shift, by one year.
EnterorSpace
Selects the focused day.
  • Days sit in a role="grid" with role="row" and role="gridcell" buttons carrying full date aria-labels, aria-selected, and aria-current="date" for today.
  • Roving tabindex keeps one day in the tab order; month changes are announced through a polite live region.
  • Previous and next buttons are labelled and use aria-disabled at the min or max month.
  • Months slide in the direction of travel while the title letters and year digits roll; the selection highlight glides between days on the morph spring.
  • Reduced motion, applied after hydration, swaps months and moves the highlight instantly.
  • The calendar is min(100%, 328px) wide and days are square cells that scale with it.
  • The header is a container query: below 260px the title takes its own row and the controls move under it.
  • Only the incoming month is observed with a ResizeObserver, to morph between four, five, and six rows.
  • Each day is a button, so a month is about 42 cells; render one calendar rather than many side by side.

Notes for AI

Give your coding assistant the Markdown reference instead of screenshots.

  • Use inline where the calendar is always visible, such as booking pages. Use date-picker for a form field that opens a calendar popover.
  • value is controlled only; month can be controlled or left internal.
  • Also exports date helpers addDays, addMonths, sameDay, and startOfDay, and the CalendarDateMatcher type.
/components/calendar/markdown

The full library index for assistants is at /llms.txt.