iconiq

Calendar

Date picker for month, year, and day selection.

Installation

npx shadcn@latest add @iconiq/calendar

Props

Calendar

shadcn-style animated monthly calendar with controlled/uncontrolled month state, day selection, and direct month/year picking.

selectedDate
Controlled selected day. When provided, the highlighted day is always derived from this prop.
defaultSelectedDate
Initial selected day for uncontrolled usage when selected is not provided.
onSelect(date: Date) => void
Called when the user picks any interactive day, including visible outside-month days.
monthDate
Controlled visible month. Prev/next, outside-day, and month/year picker navigation requests flow through onMonthChange.
defaultMonthDate
Initial visible month for uncontrolled usage when month is not provided.
onMonthChange(month: Date) => void
Called whenever the user navigates with prev/next, an outside day, or the month/year picker.
disabled(date: Date) => boolean
Marks dates as non-interactive. Disabled days keep the same visuals but cannot be selected.
localeLocale
Optional date-fns locale used for month labels, weekday headers, selected-date copy, and spoken date labels.
size"sm" | "md" | "lg"
Controls the overall calendar scale, including the card width, spacing, nav controls, weekday row, and day cell sizing. Defaults to sm.
weekStartsOn0 | 1 | 2 | 3 | 4 | 5 | 6
Overrides the first day of the week for both the weekday header and rendered month grid.
minYearnumber
Optional lower bound for selectable years in the year picker.
maxYearnumber
Optional upper bound for selectable years in the year picker.

Controlled mode: pass selected/month and respond to onSelect/onMonthChange.

Uncontrolled mode: omit selected/month and optionally seed with defaultSelected/defaultMonth.

The month and year labels open overlay pickers, so users can jump without losing the existing date-grid motion.

When no defaults are provided, the visible month starts from today and selection stays empty until the user picks a date.

Date math and layout behavior

The grid is rebuilt with date-fns whenever the visible month changes.

The rendered range runs from startOfWeek(startOfMonth(currentMonth)) through endOfWeek(endOfMonth(currentMonth)), so leading and trailing days from adjacent months are always visible.

Days outside the active month remain visible for context and can still be selected. Choosing one switches the visible month and selects that day, unless the date is marked unavailable through disabled.

Weekday headers and the grid start day now follow the provided locale/weekStartsOn settings instead of being hardcoded to English Sunday-first output.

Motion and interaction model

Month transitions, selected-day changes, and the live selection summary each animate independently.

Prev and next controls are real buttons with aria-label values, and each in-month day is rendered as a button with hover and tap motion.

Month/year picker overlays use the same smooth easing as the date grid, while directional grid changes keep the existing staggered day entrance.

The selected day highlight uses a shared layoutId of selected-day so the active surface glides between dates instead of remounting abruptly.

Keyboard users can move through the month with arrow keys, Home/End, and PageUp/PageDown, while the calendar exposes clearer spoken date labels and a live selected-date summary.

This is still not a full calendar input primitive: there is no range or multi-select mode.

Registry bundle

Install the exact registry entry shown on the right when you want the component file and its declared runtime dependencies together.

Dependencies: motion, lucide-react, date-fns.