Calendar Preview

A subcomposed calendar that owns its selection and view state.
1<CalendarPreview defaultMonth={new Date(2024, 3, 1)}>
2 <CalendarPreview.Days />
3</CalendarPreview>

Anatomy

Every part renders its own default, so composition is opt-in depth:

1import { CalendarPreview } from '@raystack/apsara'
2
3<CalendarPreview>
4 <CalendarPreview.Days />
5</CalendarPreview>

Expanded, the day view is a header and a grid:

1<CalendarPreview>
2 <CalendarPreview.Days>
3 <CalendarPreview.Header>
4 <CalendarPreview.Caption />
5 <CalendarPreview.Reset />
6 <CalendarPreview.PrevMonth />
7 <CalendarPreview.NextMonth />
8 </CalendarPreview.Header>
9 <CalendarPreview.Grid>
10 <CalendarPreview.Day />
11 <CalendarPreview.Weekday />
12 </CalendarPreview.Grid>
13 </CalendarPreview.Days>
14 <CalendarPreview.Footer />
15</CalendarPreview>

Children override the content a part computes from context, so <CalendarPreview.Caption>Q3 2024</CalendarPreview.Caption> replaces the month label.

API Reference

CalendarPreview

The root. Owns the selected value and the visible month, provides both to every part, and renders a column that hugs its content. Also takes render, className and ref.

Prop

Type

CalendarPreview.Days

The day view — a header and a grid. Hugs its content rather than reserving a fixed height.

Prop

Type

CalendarPreview.Caption

The month label above the grid, and optionally the trigger for the month and year scroller.

Prop

Type

CalendarPreview.Grid

The day grid. Layout and per-day data live here rather than on the root, so a calendar with two grids can configure them independently.

Prop

Type

CalendarPreview.Header

The row above the grid. Composes .Caption, .Reset, .PrevMonth and .NextMonth when given no children. Takes render, className and ref.

CalendarPreview.PrevMonth / CalendarPreview.NextMonth

Step the view one month. Never disabled by minDate or maxDate — bounds limit selection, not navigation.

CalendarPreview.Reset

Restores defaultDate. Renders only when there is something to restore.

CalendarPreview.Footer

The row below the calendar. A bare string is wrapped in Text; anything else renders as given.

It needs no container of its own: the root renders a column that hugs its content, so .Days and .Footer stack whatever the surrounding layout does.

useCalendar

Reads the enclosing root's state, for building parts the library does not ship. Deliberately narrow:

1import { useCalendar } from '@raystack/apsara'
2
3const { value, setValue, scale, setScale, month, setMonth, isDateUnavailable } = useCalendar()

Calling it outside a CalendarPreview throws, naming the part that asked.

Slots

Every rendered part carries a stable data-slot attribute for styling and testing:

SlotElement
calendar-previewThe root, a column wrapping the parts
calendar-preview-daysThe day view surface
calendar-preview-headerThe header row, single-month layout
calendar-preview-month-headerOne month's header, when several months are shown
calendar-preview-captionThe month label
calendar-preview-caption-popupThe month and year scroller (when dropdown is open)
calendar-preview-caption-monthsThe month column of the scroller
calendar-preview-caption-monthOne month in the scroller
calendar-preview-caption-yearsThe year column of the scroller
calendar-preview-caption-yearOne year in the scroller
calendar-preview-resetThe reset button
calendar-preview-prev-monthThe previous-month button
calendar-preview-next-monthThe next-month button
calendar-preview-gridThe grid root
calendar-preview-weeksWrapper around the table and its skeleton
calendar-preview-tableThe <table> that holds the days
calendar-preview-skeletonThe loading skeleton shown over the grid
calendar-preview-weekdayOne weekday heading
calendar-preview-dayThe <button> for a single day
calendar-preview-day-numberThe day number inside a day button
calendar-preview-day-infoContent above the number (when dateInfo resolves)
calendar-preview-day-tooltipThe tooltip shown on hover
calendar-preview-footerThe footer row
calendar-preview-footer-textThe Text wrapping a string footer

Day cells also carry their state, so a stylesheet can target it without a class:

AttributeSet when
data-selectedThe day is the committed value
data-draftThe day has roving focus but is not committed
data-unavailableThe day is out of bounds or rejected by isDateUnavailable
data-todayThe day is today
data-outsideThe day belongs to an adjacent month
data-scaleThe granularity the value is committed at

Examples

Composition

Each part renders a default; children replace it.

1<CalendarPreview defaultMonth={new Date(2024, 3, 1)}>
2 <CalendarPreview.Days />
3</CalendarPreview>

Reset

.Reset restores defaultDate and leaves the visible month alone — it is a value reset, not a view reset. It renders only when defaultDate is set and the current value differs from it, so the button disappears once there is nothing to restore.

defaultDate is a separate prop from defaultValue because defaultValue is ignored once value is passed. Keying the reset off its own prop is what makes it work for a controlled calendar.

1<CalendarPreview
2 defaultMonth={new Date(2024, 3, 1)}
3 defaultDate={new Date(2024, 3, 17)}
4 defaultValue={new Date(2024, 3, 24)}
5>
6 <CalendarPreview.Days />
7</CalendarPreview>

Selection bounds

minDate, maxDate and isDateUnavailable disable cells. None of them clamps navigation — the chevrons and the scroller still reach any month. Bounds compare whole calendar days, so a minDate carrying a time of day still leaves its own day selectable.

1<CalendarPreview
2 defaultMonth={new Date(2024, 3, 1)}
3 minDate={new Date(2024, 3, 17)}
4>
5 <CalendarPreview.Days />
6</CalendarPreview>

Grid layout

Outside days are off by default, so a grid ends on the last day of its month with the leading cells blank.

1<CalendarPreview defaultMonth={new Date(2024, 3, 1)}>
2 <CalendarPreview.Days>
3 <CalendarPreview.Header />
4 <CalendarPreview.Grid showOutsideDays />
5 </CalendarPreview.Days>
6</CalendarPreview>

Date information and tooltips

dateInfo and tooltipMessages are functions of the date, not records keyed by a formatted string. dateInfo content renders above the day number; today's dot sits below it, so the two never collide.

1<CalendarPreview defaultMonth={new Date(2024, 3, 1)}>
2 <CalendarPreview.Days>
3 <CalendarPreview.Header />
4 <CalendarPreview.Grid
5 dateInfo={(date) =>
6 date.getDate() % 7 === 0 ? (
7 <Text size="micro" variant="accent">
8 $
9 </Text>
10 ) : null
11 }
12 />
13 </CalendarPreview.Days>
14</CalendarPreview>

Month and year scroller

<CalendarPreview.Caption dropdown /> turns the caption into a filled chip that opens two adjacent scrolling columns. It is a plain popover of buttons, not a Select — picking from either column moves the view and never selects a value.

Accessibility

  • Arrow keys move between days; the focused cell carries data-draft until it is committed
  • Each grid is labelled with its month, so the caption is not the only announcement
  • Nav buttons carry aria-label, and the scroller's columns are labelled groups
  • Selected and unavailable days are announced through their native button state