Skip to content
Primitives

Calendar

Date-grid calendar (react-day-picker) re-skinned to the HUD — sharp cells, mono uppercase weekday rulers, ghost nav and a signal fill on the selected day.

● LIVE
June 2026
npx shadcn@latest add https://okibi.cndr.dev/r/calendar.json

Installation

Install the theme first, then add the component:

npx shadcn@latest add https://okibi.cndr.dev/r/calendar.json

Install the required dependencies:

npm install lucide-react react-day-picker

Add the okibi building blocks it composes: button.

Copy the source from the Code tab above into components/ui/calendar.tsx. It uses the cn helper and the okibi theme tokens — install the theme first if you haven't.

Usage

import { Calendar } from "@/components/ui/calendar"

const [date, setDate] = React.useState<Date | undefined>(new Date())

<Calendar mode="single" selected={date} onSelect={setDate} />

Examples

Range

Set mode="range" to select a span: the two ends fill signal with a dim surface strip running between them.

● LIVE
June 2026

Multiple

Set mode="multiple" to select any number of individual days; the bound value is a Date[].

● LIVE
June 2026

Dropdown navigation

captionLayout="dropdown" swaps the month/year caption for selects, bounded by startMonth/endMonth for fast travel across a wide range.

● LIVE
June 2026

Disabled dates

Pass a disabled matcher to lock out days — here weekends — so only valid dates can be picked.

● LIVE
June 2026

API Reference

Calendar

PropTypeDefaultDescription
mode"single" | "multiple" | "range""single"Selection mode.
selectedDate | Date[] | DateRangeThe current selection (matches mode).
onSelect(value) => voidFires with the new selection.
captionLayout"label" | "dropdown""label"Month/year caption as a label or dropdowns.
showOutsideDaysbooleantrueRender days spilling in from adjacent months.
buttonVariantButton variant"ghost"Variant used for the nav buttons.
numberOfMonthsnumber1How many months to render side by side.

Accessibility

  • Built on react-day-picker — days are a real grid with arrow-key navigation; autoFocus lands focus on the active day.
  • Roving focus is honored: CalendarDayButton re-focuses whenever its focused modifier flips, so keyboard movement never strands focus.
  • The focused cell gets a 2px inset ring-ring (inset, not offset, so it never clips inside the grid); nav buttons inherit the Button focus ring.
  • Disabled and outside days carry aria-disabled / muted styling but stay in the reading order so the month grid keeps its shape.
  • Chevrons flip under rtl, and weekday rulers are real <th> headers — screen readers announce the column for each day.

Guidelines

Do

  • Pass mode to match the task — single for one date, range for spans, multiple for scattered picks.
  • Use startMonth / endMonth to fence navigation and the disabled matcher to block invalid days at the source.
  • Switch captionLayout to dropdown when users jump across distant months or years.

Don't

  • Don't lean on the today cell as the only state cue — it reads like a range strip once a selection covers it; pair it with a visible label.
  • Don't drop a bare Calendar into a tight field; for a single value reach for DatePicker, which wraps it in a popover.

On this page