Back to catalog
Component detail entry
Forms
@vean/ui
SCalendar

Calendar

Calendar belongs to the Forms category. Start with demos and usage, then use the API tables to finish integration and styling decisions.

Use the quick jump panel to reach overview, usage, demos, and API first, then continue through the full page.

Quick jump

Related components

If you are composing interactions in the same family, these components usually pair well together.

Calendar

Overview

A monthly date grid that supports single or multiple selection, disabled and unavailable dates, min/max bounds, custom cell rendering, and month/year Select controls in the compact header. Use it for booking, scheduling, or any date-picking surface that needs keyboard-navigable grids instead of a plain text input. Pair it with SDatePicker when you need a popup trigger, or SRangeCalendar-style composites for range selection.

Usage

Features

  • 📅 Month grid — one or more month grids (numberOfMonths) with locale-aware weekday headers, today, and outside-view markers
  • 🎚 Controlled / uncontrolled — v-model/defaultValue for single dates or date arrays (multiple), backed by useControllableState
  • ✅ Multiple selection — click or keyboard-toggle dates; preventDeselect keeps the selection sticky
  • ⌨️ Full keyboard support — ArrowLeft/ArrowRight/ArrowUp/ArrowDown navigation with RTL reversal, cross-month paging, and disabled-date skipping; Enter/Space selects
  • ⛓ Bounds & matching — minValue/maxValue clamp the page and disable out-of-range dates; isDateDisabled/isDateUnavailable mark arbitrary dates
  • 🧩 Composable slots — day, head-cell, heading, prev, and next slots with rich slot props; *Props passthrough for every sub-part
  • 🔤 Localized UI — locale, weekStartsOn, and weekdayFormat; month/year Select controls carry localized aria-labels
  • 🗓 Month/year controls — compact header renders Select controls for fast month/year jumps, disabled per minValue/maxValue
  • ↕️ Fixed weeks — fixedWeeks renders a consistent 6-row grid; initialFocus moves focus into the grid on mount
  • 🚫 Disabled / readonly — disabled blocks all interaction; readonly keeps browsing but blocks selection

Component family

  • SCalendar — the styled wrapper that forwards props to the Aria compact and injects calendarVariants classes (12 slots, shared button icon recipes for prev/next)
  • CalendarCompact (Aria) — data-driven composition of CalendarRoot + header (prev/heading/next) + one grid per month (grid head/body rows of CalendarCellTrigger); import from @vean/aria/calendar for unstyled usage
  • CalendarRoot (Aria) — state owner: useControllableState for value/placeholder, useCalendar for grid/month pages and validation, useCalendarState for selected/invalid state
  • CalendarCellTrigger / CalendarCell / CalendarGrid* (Aria) — the editable day button (keyboard handling, focus management, data attributes) and its semantic grid cell wrappers

Demos

Basic

Event Date, April 2026

Disabled

Event Date, April 2026

Custom Styling

Event Date, April 2026

API

Aria Layer

14

Calendar<M>

40 Props2 Emits6 Slots
Props
PropTypeDefaultDescription
class
ClassValue
—
Additional class names applied to the root element.
size
ThemeSize
—
Visual size of the component.
ui
Partial<CalendarUi>
—
Per-slot class overrides for the component.
headerProps
CalendarHeaderProps
—
Properties forwarded to the header element.
headingProps
CalendarHeadingProps
—
Properties forwarded to the heading element.
prevProps
CalendarPrevProps
—
Properties forwarded to the prev element.
nextProps
CalendarNextProps
—
Properties forwarded to the next element.
gridProps
CalendarGridProps
—
Properties forwarded to the grid element.
gridHeadProps
CalendarGridHeadProps
—
Properties forwarded to the grid head element.
gridBodyProps
CalendarGridBodyProps
—
Properties forwarded to the grid body element.
gridRowProps
CalendarGridRowProps
—
Properties forwarded to the grid row element.
headCellProps
CalendarHeadCellProps
—
Properties forwarded to the head cell element.
cellProps
CalendarCellProps
—
Properties forwarded to the cell element.
cellTriggerProps
CalendarCellTriggerProps
—
Properties forwarded to the cell trigger element.
dir
Direction
—
Reading direction of the component.
locale
string
—
Locale.
modelValue
CalendarModelValue<M>
—
Current model value.
defaultValue
CalendarModelValue<M>
—
Default value.
multiple
M
—
Whether multiple values are supported.
placeholder
DateValue
—
Placeholder.
defaultPlaceholder
DateValue
—
Default placeholder.
disabled
boolean
—
Whether the component is disabled.
readonly
boolean
—
Whether the component is readonly.
pagedNavigation
boolean
—
Whether paged navigation.
preventDeselect
boolean
—
Whether prevent deselect.
weekStartsOn
WeekStartsOn
—
Week starts on.
weekdayFormat
WeekDayFormat
—
Weekday format.
calendarLabel
string
—
Calendar label.
fixedWeeks
boolean
—
Whether fixed weeks.
maxValue
DateValue
—
Max value.
minValue
DateValue
—
Min value.
numberOfMonths
number
—
Number of months.
initialFocus
boolean
—
Whether initial focus.
isDateDisabled
DateMatcher
—
Whether the date is disabled.
isDateUnavailable
DateMatcher
—
Whether the date is unavailable.
nextPage
((placeholder: DateValue) => DateValue)
—
Next page.
prevPage
((placeholder: DateValue) => DateValue)
—
Prev page.
disableDaysOutsideCurrentView
boolean
—
Whether to disable days outside current view.
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`
Emits
Emit NameParametersDescription
update:modelValue
CalendarModelValue<M>
Emitted when the model value changes.
update:placeholder
DateValue
Emitted when the placeholder value changes.
Slots
Slot NameParametersDescription
default
{ modelValue: CalendarModelValue<M>; }
Custom content for the default slot.
prev
{ disabled: boolean; }
Custom content for the prev slot.
heading
CalendarHeadingSlotProps
Custom content for the heading slot.
next
{ disabled: boolean; }
Custom content for the next slot.
head-cell
{ date: Date; index: number; label: string; }
Custom content for the head cell slot.
day
CalendarDaySlotProps
Custom content for the day slot.

CalendarCell

3 Props
Props
PropTypeDefaultDescription
date
Date
—
Date.
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`

CalendarCellTrigger

6 Props1 Slots
Props
PropTypeDefaultDescription
day
Date
—
Day.
month
Date
—
Month.
type
ButtonType
'button'
The type of the button element. Can be one of 'button', 'submit', or 'reset'.
disabled
boolean
—
Whether the component is disabled.
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`
Slots
Slot NameParametersDescription
default
CalendarCellTriggerSlotProps
Custom content for the default slot.

CalendarCompact<M>

37 Props2 Emits6 Slots
Props
PropTypeDefaultDescription
headerProps
CalendarHeaderProps
—
Properties forwarded to the header element.
headingProps
CalendarHeadingProps
—
Properties forwarded to the heading element.
prevProps
CalendarPrevProps
—
Properties forwarded to the prev element.
nextProps
CalendarNextProps
—
Properties forwarded to the next element.
gridProps
CalendarGridProps
—
Properties forwarded to the grid element.
gridHeadProps
CalendarGridHeadProps
—
Properties forwarded to the grid head element.
gridBodyProps
CalendarGridBodyProps
—
Properties forwarded to the grid body element.
gridRowProps
CalendarGridRowProps
—
Properties forwarded to the grid row element.
headCellProps
CalendarHeadCellProps
—
Properties forwarded to the head cell element.
cellProps
CalendarCellProps
—
Properties forwarded to the cell element.
cellTriggerProps
CalendarCellTriggerProps
—
Properties forwarded to the cell trigger element.
dir
Direction
—
Reading direction of the component.
locale
string
—
Locale.
modelValue
CalendarModelValue<M>
—
Current model value.
defaultValue
CalendarModelValue<M>
—
Default value.
multiple
M
—
Whether multiple values are supported.
placeholder
DateValue
—
Placeholder.
defaultPlaceholder
DateValue
—
Default placeholder.
disabled
boolean
—
Whether the component is disabled.
readonly
boolean
—
Whether the component is readonly.
pagedNavigation
boolean
—
Whether paged navigation.
preventDeselect
boolean
—
Whether prevent deselect.
weekStartsOn
WeekStartsOn
—
Week starts on.
weekdayFormat
WeekDayFormat
—
Weekday format.
calendarLabel
string
—
Calendar label.
fixedWeeks
boolean
—
Whether fixed weeks.
maxValue
DateValue
—
Max value.
minValue
DateValue
—
Min value.
numberOfMonths
number
—
Number of months.
initialFocus
boolean
—
Whether initial focus.
isDateDisabled
DateMatcher
—
Whether the date is disabled.
isDateUnavailable
DateMatcher
—
Whether the date is unavailable.
nextPage
((placeholder: DateValue) => DateValue)
—
Next page.
prevPage
((placeholder: DateValue) => DateValue)
—
Prev page.
disableDaysOutsideCurrentView
boolean
—
Whether to disable days outside current view.
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`
Emits
Emit NameParametersDescription
update:modelValue
CalendarModelValue<M>
Emitted when the model value changes.
update:placeholder
DateValue
Emitted when the placeholder value changes.
Slots
Slot NameParametersDescription
default
{ modelValue: CalendarModelValue<M>; }
Custom content for the default slot.
prev
{ disabled: boolean; }
Custom content for the prev slot.
heading
CalendarHeadingSlotProps
Custom content for the heading slot.
next
{ disabled: boolean; }
Custom content for the next slot.
head-cell
{ date: Date; index: number; label: string; }
Custom content for the head cell slot.
day
CalendarDaySlotProps
Custom content for the day slot.

CalendarGrid

2 Props
Props
PropTypeDefaultDescription
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`

CalendarGridBody

2 Props
Props
PropTypeDefaultDescription
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`

CalendarGridHead

2 Props
Props
PropTypeDefaultDescription
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`

CalendarGridRow

2 Props
Props
PropTypeDefaultDescription
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`

CalendarHeadCell

2 Props
Props
PropTypeDefaultDescription
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`

CalendarHeader

2 Props
Props
PropTypeDefaultDescription
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`

CalendarHeading

2 Props
Props
PropTypeDefaultDescription
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`

CalendarNext

5 Props
Props
PropTypeDefaultDescription
nextPage
((placeholder: DateValue) => DateValue)
—
Next page.
type
ButtonType
'button'
The type of the button element. Can be one of 'button', 'submit', or 'reset'.
disabled
boolean
—
Whether the component is disabled.
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`

CalendarPrev

5 Props
Props
PropTypeDefaultDescription
prevPage
((placeholder: DateValue) => DateValue)
—
Prev page.
type
ButtonType
'button'
The type of the button element. Can be one of 'button', 'submit', or 'reset'.
disabled
boolean
—
Whether the component is disabled.
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`

CalendarRoot<M>

26 Props2 Emits1 Slots
Props
PropTypeDefaultDescription
dir
Direction
—
Reading direction of the component.
locale
string
—
Locale.
modelValue
CalendarModelValue<M>
—
Current model value.
defaultValue
CalendarModelValue<M>
—
Default value.
multiple
M
—
Whether multiple values are supported.
placeholder
DateValue
—
Placeholder.
defaultPlaceholder
DateValue
—
Default placeholder.
disabled
boolean
—
Whether the component is disabled.
readonly
boolean
—
Whether the component is readonly.
pagedNavigation
boolean
—
Whether paged navigation.
preventDeselect
boolean
—
Whether prevent deselect.
weekStartsOn
WeekStartsOn
—
Week starts on.
weekdayFormat
WeekDayFormat
—
Weekday format.
calendarLabel
string
—
Calendar label.
fixedWeeks
boolean
—
Whether fixed weeks.
maxValue
DateValue
—
Max value.
minValue
DateValue
—
Min value.
numberOfMonths
number
—
Number of months.
initialFocus
boolean
—
Whether initial focus.
isDateDisabled
DateMatcher
—
Whether the date is disabled.
isDateUnavailable
DateMatcher
—
Whether the date is unavailable.
nextPage
((placeholder: DateValue) => DateValue)
—
Next page.
prevPage
((placeholder: DateValue) => DateValue)
—
Prev page.
disableDaysOutsideCurrentView
boolean
—
Whether to disable days outside current view.
asChild
boolean
—
Change the default rendered element for the one passed as a child, merging their props and behavior.
as
AsTag | Component
'div'
The element or component this component should render as. Can be overwrite by `asChild`
Emits
Emit NameParametersDescription
update:modelValue
CalendarModelValue<M>
Emitted when the model value changes.
update:placeholder
DateValue
Emitted when the placeholder value changes.
Slots
Slot NameParametersDescription
default
CalendarRootSlotProps<M>
Custom content for the default slot.

Notes

Architecture and benchmark differences

CalendarRoot owns the value via useControllableState (single date or array when multiple), keeps the placeholder for grid paging, and delegates grid creation to useCalendar (which rebuilds the grid on locale/week-start/placeholder changes and clamps pages with minValue/maxValue). useCalendarState derives selected/invalid state. CalendarCellTrigger is the only interactive piece: it reads the shared context, computes data-focused/data-selected/data-today/data-unavailable/data-outside-view, handles Arrow/Enter/Space keys with dir-aware direction (RTL flips ArrowLeft/ArrowRight), and pages to adjacent months when navigation crosses the grid boundary. The compact owns iteration over months/weeks/days and the header wiring (prev/heading/next with month/year Select controls). Most benchmark libraries ship a monolithic calendar panel; the Aria/styled split, per-part *Props passthrough, and slot-driven cell rendering are the differentiators.

CapabilityVeanUIAnt DesignElement PlusMantineNaive UIshadcn
Aria/styled split✅—————
Single / multiple selection✅✅✅✅✅—
Keyboard grid navigation✅✅✅✅✅✅
RTL direction reversal✅—————
numberOfMonths grid✅——✅——
minValue/maxValue bounds✅✅✅✅✅—
isDateDisabled / unavailable✅✅✅✅✅—
fixedWeeks / weekStartsOn✅—✅✅——
Month/year Select controls✅✅✅———
Custom prevPage/nextPage✅—————
Per-part *Props passthrough✅—————
Localized aria-labels✅✅✅✅——

Cautions

  • The value is a native Date at local midnight (the DateValue model: Date or { date, time? }). Use date-fns or Intl when formatting or converting.
  • multiple changes the model shape to DateValue[]; the M generic infers it from the prop.
  • defaultValue/defaultPlaceholder are read on mount only — use v-model for external control.
  • isDateDisabled and isDateUnavailable differ: disabled dates are unselectable by policy, unavailable dates are additionally marked visually (line-through in the default style).
  • Dates outside the current month are rendered by default; pass disableDaysOutsideCurrentView to disable them.
  • The prev/next aria-labels default to locale messages; override per button through prevProps/nextProps.
  • Navigation buttons auto-disable at minValue/maxValue; custom prevPage/nextPage functions take part in that computation.

FAQ

How do I select multiple dates?

Pass multiple (boolean shorthand works in templates) and bind v-model to an array of DateValues. Clicking toggles dates; preventDeselect stops removal.

How do I prevent dates before today?

Pass minValue={new Date(2026, 0, 1)} (or any DateValue). Out-of-range dates are disabled and the prev button auto-disables at the bound.

How do I show several months at once?

Set numberOfMonths={2} — the calendar renders two month grids side by side and pages both when crossing the boundary.

Why is PageUp/PageDown not handled?

Grid navigation currently covers Arrow keys, Enter/Space, and cross-month paging. PageUp/PageDown/Home/End (present in Ant Design/Element Plus panels) are a scheduled enhancement.

How do I build a date range with this component?

Use SRangeCalendar for a dedicated range grid, or pair two SCalendars with minValue/maxValue bound to the other side’s selection.

Changelog

Version history is grouped by release so you can quickly see what changed for this component across published versions.

v0.17.0

2026-05-03

Compare release

Optimization

remove unused props and update readonly binding

Scope: calendarAuthors: soybeanjsView commitaed69

v0.16.0

2026-05-01

Compare release

Optimization

add compact header with month/year select and improve calendar functionality

Scope: calendarAuthors: soybeanfe, CopilotView commit2d4e6