ComponentsEvents & BookingBooking Calendar

Events & Booking

Booking Calendar

Full booking flow in one component - month picker, time-slot selector, optional Stripe payment, and booking creation. Reads Opening Hours for availability, supports date overrides and blocked dates, and navigates to Booking List after confirmation.

Slot source priorityBackend → override → hours → legacy

Backend availability wins when it returns data. Falls back through date overrides, Opening Hours schedule, then legacy props.

PaymentStripe · free-service bypass

Paid services go through PaymentSheet or browser checkout. Free services skip payment entirely.

TierFree

Available on all plans.

What it does

Four things worth knowing

Slot resolution has a strict priority order

For any selected day, slots come from: (1) backend useAvailableSlots when non-empty, (2) dateOverrides for that date, (3) generated slots from the Opening Hours schedule for that weekday, (4) legacy businessHours / openingTime / closingTime props. Blocked and special closed dates always force no slots regardless of priority.

Opening Hours is the source of truth for availability

The component hydrates Opening Hours from _prefetchedOpeningHours in builder preview, or from the Opening Hours API endpoint at runtime. If Opening Hours data is unavailable, legacy props are used as fallback. Keep your Opening Hours component published and accurate - this calendar reads the same schedule.

Booking window is controlled by monthsToShow

monthsToShow (1–12) sets how far forward users can book. A “Booking window: X month(s)” indicator is shown on the calendar. Users can browse up to 12 months forward but can only select dates within the window. A legacy daysToShow prop is automatically converted to months when monthsToShow is absent.

Payment blocks confirmation for paid services

When a service has a price > 0, the component attempts native Stripe PaymentSheet first, then browser checkout session, then PaymentIntent fallback. If none succeed, booking is blocked. Free services skip payment and set paymentStatus to free automatically - no configuration needed.

Builder setup

Find it, drop it, wire the screens

Where to find itAdd it to any booking screen

  1. Component picker → Events & BookingBooking Calendar.
  2. Drop it on the screen where users select a date and time.
  3. Pair it with a Booking List screen as the post-confirmation destination.

Before you publishThree things to check

  1. Set bookingListScreenId so the user lands on their bookings after confirming.
  2. Set monthsToShow to match how far in advance your service accepts bookings.
  3. Publish your Opening Hours component first - slot availability reads from the same schedule.
Category: Events & BookingComponent: BuilderBookingCalendarRegistry key: booking-calendarTier: Free
Props

Booking window, slots, and navigation

PropTypeDefaultDescription
monthsToShownumber1How many months forward users can book (1–12).
timeSlotsarray-Explicit time slot list. When set, overrides generated slots.
businessHoursobject-Legacy per-day hours map. Used when Opening Hours data is unavailable.
blockedDatesstring[][]Dates that are always unavailable regardless of other slot sources.
dateOverridesobject-Per-date slot overrides. Applied after backend, before Opening Hours fallback.
slotDurationMinutesnumber-Slot length used when generating slots from opening hours.
bookingListScreenIdstring-Screen to navigate to after successful booking confirmation.
backScreenIdstring-Screen to navigate to on back action.
Toggles & colours

Make it yours

Every colour and visibility toggle below is yours to change. The defaults are a neutral starting point - adjust them to match the brand without touching anything else.

PropDefaultWhat it controls
showProviderInfotrueProvider name and avatar above the calendar.
showPricetrueService price shown in the booking summary.
showDurationtrueService duration shown in the booking summary.
showConfirmButtontrueConfirm / pay button visibility.
dayActiveBackgroundColor#007AFFBackground of the selected day in the calendar.
dayInactiveBackgroundColor#F3F4F6Background of unavailable / out-of-window days.
slotAvailableBackgroundColor#F0F9FFBackground of an available time slot.
slotUnavailableBackgroundColor#F3F4F6Background of an unavailable time slot.
slotSelectedBackgroundColor#007AFFBackground of the currently selected time slot.
slotSelectedColor#FFFFFFText colour of the selected time slot.
confirmButtonColor#007AFFConfirm / pay button background.
confirmButtonTextColor#FFFFFFConfirm / pay button label colour.
borderRadius8Corner radius applied to calendar cells and slot chips.
Tips

Common mistakes to avoid

No slots showing on a day

Check in order: is the day in blockedDates or specialClosedDates? Is Opening Hours marking that weekday as closed? Is the backend returning an empty array due to an endpoint or data issue? Are dateOverrides accidentally setting an empty slot list for that date?

Confirm button does nothing for paid services

Paid booking confirmation requires secureApiCall and a valid appId to be present in the player context, and Stripe endpoints must be configured server-side. If either is missing, the booking is intentionally blocked.

Selected slot disappears after refresh

This is expected behaviour. If the selected slot becomes unavailable after a background refresh, the stale selection is invalidated automatically. It is not a bug - it prevents double-booking.

Publish Opening Hours before testing slots

The calendar reads the Opening Hours schedule from the backend. If Opening Hours has never been published, or has unpublished changes, slot generation will fall back to legacy props or produce no slots. Publish Opening Hours first, then test the calendar.