Phase 9d · Tier B

RN-universal Calendar pilot

Scaffolded

Month-grid date picker with single, multiple, and range modes. Mirrors the shadcn Calendar surface (which wraps react-day-picker). Hand-rolled — no new runtime dep. Same code path on web and native.

Side-by-side: single date

shadcn (react-day-picker)
SuMoTuWeThFrSa

Selected: Fri May 01 2026

RN
May 2026
Sun
Mon
Tue
Wed
Thu
Fri
Sat

Selected: Fri May 01 2026

Multiple selection

Tap to toggle. Tap an already-selected day to deselect.

May 2026
Sun
Mon
Tue
Wed
Thu
Fri
Sat

0 day(s) selected: (none)

Range selection (with weekends disabled)

First tap sets the start; second tap sets the end. Tapping a third time starts a new range.

May 2026
Sun
Mon
Tue
Wed
Thu
Fri
Sat
26
2
3
9
10
16
17
23
24
30
31
6

From: (none) · To: (none)

From / to bounds

Constrain selectable dates with fromDate and toDate (e.g. an admissions intake window).

May 2026
Sun
Mon
Tue
Wed
Thu
Fri
Sat
26
27
28
29
30
1
2
3
4
5
6

Library decision

Per Phase 9 Q2, every Tier B primitive must record its library choice. RnCalendar ships with no new runtime dependency.

  • react-day-picker — web-only (DOM<table> / <button> elements + DOM event handlers). Same .web/.native blocker as cmdk / sonner / input-otp.
  • react-native-calendars@1.1314.0 (MIT, ~454 k/wk) — RN-only; not RN-Web-friendly. Adopting both would force a .web/.native split that no other Phase 9d primitive uses.
  • react-native-modal-datetime-picker (~700 k/wk) — modal wrapper around the OS pickers; surface doesn't match shadcn's inline grid.
  • @expo/react-native-calendar-picker (~30 k/wk) — lacks range mode.
  • This implementation — pure RN core. Date API for math, View / Pressable / Text for the grid. ~280 LOC; same shape as our other no-deps primitives.

Semantics

Aspectshadcn (react-day-picker)RNNotes
Modessingle / multiple / rangesingle / multiple / rangeSame surface
Disabled datesarray or function or matcherarray or functionSubset of shadcn (no DateMatcher complex types)
Range boundsfromDate / toDate / disabledfromDate / toDate / disabledSame
Outside daysshowOutsideDaysshowOutsideDaysSame default true
Localereact-intl / dateFnsLocaleweekdayLabels + monthLabel propsConsumer brings their own i18n
Multiple monthsnumberOfMonthssingle only in v10.3.x candidate
Keyboard navarrow keystap (Tab on RN-Web)0.3.x candidate