Docyrus

TimeSlotScheduler

Calendly-style booking scheduler — generated slots with capacity, reservations and disabled reasons, a paged week view, a month view with availability dots, and a user / event / timezone summary card.

iOSAndroid
Preview TimeSlotScheduler on your device

Scan with Expo Go

Download Expo Go, then scan the QR code to preview native components.

Installation

pnpm dlx @docyrus/cli add @docyrus/rn-time-slot-scheduler
Required Packages(1 package)
pnpm add date-fns

Usage

import { TimeSlotScheduler } from '@/components/docyrus-native/time-slot-scheduler';
import type { SlotSelectPayload, TimeSlotReservation } from '@/components/docyrus-native/time-slot-scheduler';

const reservations: TimeSlotReservation[] = [
  { id: 'r1', name: 'Ayşe Demir', email: 'ayse@example.com', startTime: '2026-09-24T10:00:00.000Z', endTime: '2026-09-24T10:30:00.000Z' },
];

const [slot, setSlot] = useState<SlotSelectPayload | null>(null);

<TimeSlotScheduler
  startTime="09:00"
  endTime="17:00"
  slotSize={30}
  slotCapacity={3}
  reservations={reservations}
  unavailableSlots={[{ day: '1', startTime: '12:00', endTime: '13:00' }]}
  user={{ fullName: 'Erhan Erdoğan', email: 'erhan@example.com' }}
  event={{ subject: 'Product demo', duration: '30 min', location: 'Google Meet' }}
  timezones={[{ value: 'Europe/Istanbul', label: 'Istanbul', offset: 'GMT+3' }]}
  defaultTimezone="Europe/Istanbul"
  showReservationDetail
  selectedSlot={slot}
  onSelect={setSlot}
/>

Multiple selection (native-only)

const [slots, setSlots] = useState<SlotSelectPayload[]>([]);

<TimeSlotScheduler
  selectionMode="multiple"
  selectedSlots={slots}
  onSelectionChange={setSlots}
/>

Behavior

  • Slot generation — slots are generated from startTime → endTime in slotSize steps (shared logic with web: lib/time-slot-utils.ts). Each slot gets a status: available, partial (some capacity used), full, unavailable (inside an unavailableSlots range), past, or disabled (outside minDate / maxDate), plus a disabledReason.
  • Columns mode — the week (Monday start, weekends only when showSaturday / showSunday) as a horizontally paged day list: 3 day columns per page in portrait, 5 in landscape, or columnsPerPage. The header navigates week by week and has a Today button.
  • Month mode — the native MiniCalendar with a dot on every day that still has an available or partial slot, and the picked day's slot list below it. Month navigation is handled by the calendar itself. The list always shows a day (the anchor date until another day is picked), unlike web which shows a "select a day" prompt.
  • Selecting — tap an enabled slot to select it (onSelect with an ISO SlotSelectPayload). In selectionMode="multiple" a tap toggles the slot and onSelectionChange receives the full selection.
  • Reservations — with showReservationDetail, long-press a slot to open a bottom sheet listing its reservations (web: popover). Tapping a disabled slot opens the same sheet with the disabled reason (web: tooltip).
  • Summary card — user, event and timezones render in a collapsible header card (web: sidebar). The timezone select only reports the value (onTimezoneChange); slot times are not converted, same as web.
  • Formatting — slot times use useDateFormat().formatTime when a DateFormatProvider / DocyrusTenantProvider is mounted, otherwise the web h:mm AM format. All copy goes through useUiTranslation() with the web ui.timeSlot.* keys.

API Reference

PropTypeDefaultDescription
startTimestring'09:00'Start of the bookable day (HH:mm).
endTimestring'17:00'End of the bookable day (HH:mm).
slotSizenumber30Slot length in minutes.
slotCapacitynumber1Bookings allowed per slot. When > 1, slots show a count/capacity indicator.
reservationsTimeSlotReservation[][]Existing bookings; a reservation counts against every slot it overlaps.
unavailableSlotsUnavailableRange[][]Blocked ranges per date or recurring weekday.
userSchedulerUser—Host shown in the summary card.
eventSchedulerEvent—Bookable event shown in the summary card.
mode'columns' | 'month'—Controlled view mode.
defaultMode'columns' | 'month''columns'Initial view mode (uncontrolled).
onModeChange(mode: TimeSlotSchedulerMode) => void—Fires when the view mode toggle changes.
defaultDateDatenew Date()Initial anchor date.
minDateDate—Slots starting before this are disabled (before-min-date).
maxDateDate—Slots starting after this are disabled (after-max-date).
showSaturdaybooleanfalseInclude Saturdays.
showSundaybooleanfalseInclude Sundays.
timezonestring—Controlled timezone value.
defaultTimezonestring''Initial timezone value (uncontrolled).
timezonesTimezoneOption[][]Options for the timezone select. The select is hidden when empty.
onTimezoneChange(tz: string) => void—Fires when the timezone changes.
showReservationDetailbooleanfalseLong-press a slot to list its reservations in a bottom sheet.
selectedSlotSlotSelectPayload | null—Controlled single selection.
defaultSelectedSlotSlotSelectPayload | nullnullInitial single selection (uncontrolled).
onSelect(payload: SlotSelectPayload) => void—Fires when a slot is selected (in multiple mode: when a slot is toggled on).
selectionMode'single' | 'multiple''single'Native-only. 'multiple' lets the user toggle several slots.
selectedSlotsSlotSelectPayload[]—Native-only. Controlled multiple selection.
defaultSelectedSlotsSlotSelectPayload[][]Native-only. Initial multiple selection (uncontrolled).
onSelectionChange(slots: SlotSelectPayload[]) => void—Native-only. Fires with the full selection after every toggle.
columnsPerPagenumber3 portrait / 5 landscapeNative-only. Day columns visible per page in columns mode.
defaultSummaryOpenbooleanfalseNative-only. Start the user / event summary card expanded.
classNamestring—Additional classes for the root container.

TimeSlotReservation

PropertyTypeDescription
idstringUnique id.
namestringPerson who booked.
emailstringOptional email.
avatarUrlstringOptional avatar image.
startTimestringISO date-time.
endTimestringISO date-time.

UnavailableRange

PropertyTypeDescription
daystringyyyy-MM-dd for one date, or '0'–'6' (Sunday–Saturday) for a recurring weekday.
startTimestringHH:mm.
endTimestringHH:mm.

SchedulerUser

PropertyTypeDescription
fullNamestringHost name (initials are used when there is no avatar).
emailstringOptional email.
avatarUrlstringOptional avatar image.

SchedulerEvent

PropertyTypeDescription
subjectstringEvent title.
durationstringDisplay duration, e.g. '30 min'.
locationstringOptional location.
descriptionstringOptional description.
iconReactNodeOptional icon element.

TimezoneOption

PropertyTypeDescription
valuestringTimezone id, e.g. 'Europe/Istanbul'.
labelstringDisplay label.
offsetstringDisplay offset, e.g. 'GMT+3'.

SlotSelectPayload

PropertyTypeDescription
dayDateDay of the slot.
startTimestringHH:mm.
endTimestringHH:mm.
startISOstringISO start.
endISOstringISO end.
capacitynumberSlot capacity.
reservationCountnumberOverlapping reservations.
remainingCapacitynumbercapacity - reservationCount (min 0).
reservationsTimeSlotReservation[]Overlapping reservations.

TimeSlot / DaySlots

TimeSlot is the generated slot (id, day, startTime, endTime, startISO, endISO, status: SlotStatus, disabledReason?: DisabledReason, capacity, reservationCount, remainingCapacity, reservations). DaySlots groups a day's slots (date, dayLabel, dateLabel, fullLabel, isToday, isWeekend, slots, hasAvailability).

Translation keys

ui.timeSlot.previousWeek, ui.timeSlot.nextWeek, ui.common.today, ui.timeSlot.columnsView, ui.timeSlot.monthView, ui.timeSlot.duration, ui.timeSlot.location, ui.timeSlot.timezone, ui.timeSlot.selectTimezone, ui.timeSlot.noSlotsAvailable, ui.timeSlot.of, ui.timeSlot.booked, ui.timeSlot.pastSlot, ui.timeSlot.full, ui.timeSlot.unavailable, ui.timeSlot.beforeMinDate, ui.timeSlot.afterMaxDate — the same keys as the web component.

Type Exports

TypeDescription
TimeSlotSchedulerPropsProps for TimeSlotScheduler.
TimeSlotSchedulerMode'columns' | 'month'.
TimeSlotSelectionModeNative-only. 'single' | 'multiple'.
SlotStatus'available' | 'partial' | 'full' | 'unavailable' | 'past' | 'disabled'.
DisabledReason'past' | 'full' | 'unavailable' | 'before-min-date' | 'after-max-date'.
TimeSlotA generated slot.
DaySlotsA day with its slots.
TimeSlotReservationAn existing booking.
UnavailableRangeA blocked range.
SchedulerUserHost for the summary card.
SchedulerEventEvent for the summary card.
TimezoneOptionTimezone select option.
SlotSelectPayloadPayload passed to onSelect / onSelectionChange.

On this page