Calendar
Dependency-free month-grid date picker. The header can stay simple or become an interactive month/year chooser.
Basic
The default header is a plain, non-clickable month label.
- Follows the ARIA APG date-grid pattern: Arrow keys move by day, Home/End jump to the start/end of the week, and Page Up/Down move a month - only one date is a Tab stop at a time.
- The grid renders at a fixed 280px width regardless of viewport, which fits down to the smallest supported phone widths without its own responsive breakpoints.
Interactive month/year header
Set interactiveHeader to open a compact month and year chooser anchored inside the calendar. Years run from the current year back 100 years, respecting min/maxDate.
Min and max range
Days outside the allowed range are disabled.
When to use
- The date grid should always be visible - inline scheduling, a booking page, a dashboard filter that's used often.
- As the anchored popup inside Date Picker, when a compact text-field trigger is what you actually want on the page.
When not to use
- A single date field in a form where screen space matters - use Date Picker so the grid only appears on demand.
- Time selection - pair it with Time Picker rather than extending Calendar itself.
Keyboard
Mobile behavior
- Fixed 280px grid width fits down to the smallest supported phone widths without a separate mobile layout.
- Day cells meet a 44px touch target even though the grid itself is compact.
Accessibility notes
- Follows the ARIA APG date-grid pattern with role="grid" and a roving tabindex - only the focused date is a Tab stop.
- SSR-safe "today": the initial render uses a UTC-normalized date so server and client markup match, then corrects to the visitor's local today after mount if they differ - never a hydration mismatch.
Common mistakes
- Passing a raw `new Date()` for `value`/`defaultValue` in a Server Component tree - use a UTC-normalized date (see the Basic example above) to avoid a timezone-dependent hydration mismatch.
- Setting minDate after maxDate (or vice versa) - the grid will show every day disabled with no explicit empty-state messaging.
Known limitations
- Single-month view only - no built-in multi-month or date-range selection.
Related components
Calendar props
Controlled selected date.
Uncontrolled initial date.
Dates outside this range render disabled.
Makes the month/year label open a compact chooser instead of a static label.
Locale used for month/weekday names.
API reference
Controlled selected date.
Uncontrolled initial date.
Fires when a day is selected.
Earliest selectable date.
Latest selectable date.
BCP-47 locale for month and weekday names.
Make the header month/year an interactive chooser.
Additional classes applied to the component root.
