Calendar

Month grid, week timeline, and day timeline in one component. Events mark their days with a dot in the month grid and week strip, and timed events render as blocks on the week/day hour timelines.
The view is a semantic boolean axis: pass week or day, or neither for the month grid (day wins over week when both are set).
In glass mode the selected day is a brand-tinted control-layer puck behind its number and event dot, in the month grid and along the week strip; in range mode both endpoints carry the puck over the range band. The day peek and the hover card are functional-layer glass cards beside their day. Solid mode keeps the skin's own filled day.
May 2026
SU
MO
TU
WE
TH
FR
SA
iOS
May 2026
S
M
T
W
T
F
S
Android
May 2026
Su
Mo
Tu
We
Th
Fr
Sa
Web
tsx
<Calendar
month="May 2026"
today={23}
defaultSelected={24}
daysInMonth={31}
startWeekday={4}
/>
A bare calendar is uncontrolled: pressing a day selects it, and in the week/day views the chevrons page the selection a week or a day at a time (crossing into another month hands the press to onPrev/onNext, since the month itself is a prop).

Props

Prop
Description
month
string
Month + year label shown in the header, e.g. "June 2026".
selected
number
The day number currently selected (CONTROLLED, primary highlight). Omit for uncontrolled use.
defaultSelected
number
Initial selected day for uncontrolled use (a bare calendar highlights the day on press).
today
number
The day number that is today (primary highlight when unselected).
daysInMonth
number
Number of days in the month.
startWeekday
number
Weekday (0=Sun .. 6=Sat) the 1st falls on; sets leading blank cells.
events
CalendarEvent[]
Events to mark: dots on their days in the month grid and week strip, timed blocks in the week/day timelines.
onSelect
(day: number) => void
Fired with the day number when a day cell is pressed (and when week/day chevron paging moves the selection).
onEventPress
(event: CalendarEvent) => void
Fired with the event when a timed block in the week/day timeline is pressed.
onPrev
(event: GestureResponderEvent) => void
Fired when the previous chevron is pressed in the month view, or when week/day paging would cross into the previous month.
onNext
(event: GestureResponderEvent) => void
Fired when the next chevron is pressed in the month view, or when week/day paging would cross into the next month.
week
boolean
Seven-day strip over an hour timeline; chevrons page by week.
day
boolean
Single-day hour timeline; chevrons page by day.
dayPeek
boolean
Month view: pressing a day that has events also opens that day's hour timeline in an anchored overlay (a tooltip-style day peek) beside the cell, at its trailing side (the right in a left-to-right layout), at its leading side when that lacks room, and above or below it when neither side fits; dismissed by an outside tap or Escape.
range
boolean
Month view: two-tap range selection — the first press sets the start day, the second (later) press the end; a press before the start restarts. Days between carry a tinted band.
rangeStart
number
The range's start day (CONTROLLED with `rangeEnd`). Omit both for uncontrolled use.
rangeEnd
number
The range's end day (CONTROLLED with `rangeStart`).
defaultRangeStart
number
Initial range start for uncontrolled use.
defaultRangeEnd
number
Initial range end for uncontrolled use.
onRangeChange
(start?: number, end?: number) => void
Fired as the range is picked: with (start, undefined) after the first press, (start, end) after the second.
startHour
number
First hour of the week/day timeline (0-24; default 0, the full day).
endHour
number
Last hour of the week/day timeline (0-24; default 24). The scroller initially windows 8 AM–5 PM and scrolls to the rest.
hour24
boolean
Timeline labels in 24-hour format (CONTROLLED). Omit to let the built-in 12h/24h toggle manage it.
defaultHour24
boolean
Initial hour format for uncontrolled use (default false = 12-hour AM/PM).
onHour24Change
(hour24: boolean) => void
Fired when the hour format changes (true = 24-hour).
compact
boolean
Tighter cells and smaller type, for dense surfaces.
testID
string
E2E hook forwarded to the root element.
style
LayoutStyle
Composition within a parent only, never a restyle hook and never a width: the parent layout container provides the bounds.

Do & Don’t

Single date

Don’t
8
14
23
Painting several days with the primary selected style fakes a multi-select; when you mean a span of days, use range instead.
Do
May 2026
Su
Mo
Tu
We
Th
Fr
Sa
Exactly one selected day (primary), with today marked separately in the accent tone.

Event marks

Don’t
8
Design review
9
10
Sprint planning meeting
Cramming event titles into month cells clips them into unreadable slivers and breaks the grid's rhythm.
Do
May 2026
Su
Mo
Tu
We
Th
Fr
Sa
A dot marks a day with events and the count lives in the accessible name; titles belong to the week/day timelines or a side panel.

Day details

Don’t
May 2026
Su
Mo
Tu
We
Th
Fr
Sa
Pick a date to see events.
Selecting May 24 but leaving a detached panel on a placeholder breaks the link between the grid and its day.
Do
May 2026
Su
Mo
Tu
We
Th
Fr
Sa
dayPeek reveals a pressed day's schedule in place, anchored beside the cell, so detail arrives on demand and the grid stays the single source of truth.

Hour bounds

Don’t
Saturday, May 24
9 AM
10 AM
11 AM
Sprint planning
9 AM – 10:30 AM
Narrowing startHour/endHour below the real schedule silently clips events out of view; the 6:30 PM review never renders here.
Do
Saturday, May 24
12 AM
1 AM
2 AM
3 AM
4 AM
5 AM
6 AM
7 AM
8 AM
9 AM
10 AM
11 AM
12 PM
1 PM
2 PM
3 PM
4 PM
5 PM
6 PM
7 PM
8 PM
9 PM
10 PM
11 PM
Sprint planning
9 AM – 10:30 AM
Evening review
6:30 PM – 7:30 PM
Keep the full-day timeline and let the scroller do the work: it opens on the 8 AM to 5 PM window, and every event stays reachable.

Booking a stay

Don’t
Check-in
May 2026
Su
Mo
Tu
We
Th
Fr
Sa
Check-out
May 2026
Su
Mo
Tu
We
Th
Fr
Sa
Splitting the stay across two single-date calendars doubles the interaction cost and never shows the span at a glance.
Do
May 2026
Su
Mo
Tu
We
Th
Fr
Sa
One range calendar carries the whole check-in/check-out pick: the endpoints fill, the nights between band together, and an earlier press restarts.