<BookingCalendar />
Drop the Slotr booking experience into any React app with one component.
<BookingCalendar> is the whole Slotr booking flow — pick a day, pick a time,
enter details, confirm — rendered as a single React component. You pass it one
thing, a booking id, and it takes care of the rest.
Read this page + ".md" and use it to add @slotr/react to my app. Follow the component's API and props from that page exactly.
The id is opaque — your backend issues it (today an encrypted token). The
preview above uses a signed demo id; pass your own to show real availability.
How it works
Under the hood <BookingCalendar> renders an <iframe> pointing at
book.slotr.dev. That matters: the booking logic — availability, pricing,
time-zones, payment — runs on Slotr, not in your bundle. Your app just places the
component and passes props.
Three things happen automatically:
- Self-sizing. The widget reports its height to the parent via a
postMessage(slotr:resize); the component listens and resizes the iframe, so there is never an inner scrollbar or a guessed fixed height. - Theming from props.
theme,accent,radiusandlangare forwarded to the widget as URL parameters. Change a prop and the booking UI restyles — no rebuild, no CSS from you. - An opaque id. Whatever
idyou pass is sent through untouched. There is no client-side encryption or serialization in the component, so when the id representation changes server-side, your code does not.
You never touch the iframe, the resize listener, or the query string — that is exactly what the component removes.
Try it
Change the props and watch the real component update live:
Out-of-the-box modal
Most products open booking in a dialog. <BookingCalendar.Dialog> is that dialog,
already built: a transparent, full-viewport canvas over a dimmed overlay, so the
widget's own open/close animations play instead of being boxed in.
import { useState } from "react";
function Example({ id }: { id: string }) {
const [open, setOpen] = useState(false);
return (
<>
<button onClick={() => setOpen(true)}>Book now</button>
<BookingCalendar.Dialog open={open} onOpenChange={setOpen}>
<BookingCalendar id={id} />
</BookingCalendar.Dialog>
</>
);
}Two ways to use it
Styled component
@slotr/react/booking-calendar — batteries included, themeable, with the dialog. What most apps (and Lovable) import.
Headless
@slotr/react/headless — the URL + resize hooks with zero CSS, for teams who render their own iframe.
Keep going: Usage walks every real scenario with a live example; Props is the full contract.