Booking / Reservation Form React component
A booking form in one card: service cards, a month calendar with closed days and keyboard navigation, time slots built from your opening hours with booked ones struck out, a guest counter, contact fields, a live summary and a confirmation screen.
About the Booking / Reservation Form component
Booking / Reservation Form puts the whole booking flow in one card: pick a service, a day on the calendar and a free time, add the number of guests and your details, and see a summary before you book. Closed days, past days and days too far ahead are disabled, and time slots already taken are struck out.
Time slots are built from your opening hours, the slot interval and the length of the chosen service, so a 90 minute session never runs past closing. Your onBook promise drives the button; success shows a confirmation with the details and a button to book another time.
When to use it
Use it for salons, studios, clinics, consultants, restaurants or any service that books by the slot.
Connect isBooked to your availability so taken times show as unavailable before people pick them.
Installation
Add the Booking / Reservation Form component to your project with the shadcn CLI. It lands in components/booking-reservation-form.tsx as plain React + Tailwind CSS source you own and can edit.
npx shadcn@latest add @reactframe/booking-reservation-formOr copy the source by hand and install its dependencies:
npm install motion clsx tailwind-mergeProps
<BookingReservationForm /> accepts 12 props, all optional.
| Prop | Type | Default |
|---|---|---|
| title | string | "Book a session" |
| description | string | "Pick a service, a day and a time. You will get a confirmation by email straight away." |
| services Services or table types to choose from. Pass [] to skip the step. | { id: string; name: string; duration: number; price?: number; description?: string }[] | DEFAULT_SERVICES |
| guests Party size picker. Set max to 1 to hide it. | { min: number; max: number; default: number } | null | { min: 1, max: 6, default: 2 } |
| hours Opening time and closing time, 24 hour, and the gap between slots in minutes. | { open: string; close: string; step: number } | { open: "09:00", close: "18:00", step: 30 } |
| closedDays Days of the week you are closed, 0 = Sunday. | number[] | [0] |
| daysAhead How many days ahead people can book. | number | 42 |
| isBooked Return true for slots that are already taken. Defaults to a fixed demo pattern. | (date: string, time: string) => boolean | demoBooked |
| currency | string | "€" |
| onBook Called with the booking. Return a promise: the button spins while it runs, a rejection (or a returned string) shows an error, and success shows the confirmation. | (data: BookingData) => void | string | Promise<void | string> | — |
| theme | "dark" | "light" | "dark" |
| className | string | — |
- titlestringDefault: "Book a session"
- descriptionstringDefault: "Pick a service, a day and a time. You will get a confirmation by email straight away."
- services
Services or table types to choose from. Pass [] to skip the step.
{ id: string; name: string; duration: number; price?: number; description?: string }[]Default: DEFAULT_SERVICES - guests
Party size picker. Set max to 1 to hide it.
{ min: number; max: number; default: number } | nullDefault: { min: 1, max: 6, default: 2 } - hours
Opening time and closing time, 24 hour, and the gap between slots in minutes.
{ open: string; close: string; step: number }Default: { open: "09:00", close: "18:00", step: 30 } - closedDays
Days of the week you are closed, 0 = Sunday.
number[]Default: [0] - daysAhead
How many days ahead people can book.
numberDefault: 42 - isBooked
Return true for slots that are already taken. Defaults to a fixed demo pattern.
(date: string, time: string) => booleanDefault: demoBooked - currencystringDefault: "€"
- onBook
Called with the booking. Return a promise: the button spins while it runs, a rejection (or a returned string) shows an error, and success shows the confirmation.
(data: BookingData) => void | string | Promise<void | string> - theme"dark" | "light"Default: "dark"
- classNamestring
npm dependencies
Installed for you by the shadcn CLI.
Booking / Reservation Form FAQ
- How do I show real availability?
- Pass isBooked(date, time), which receives the day as YYYY-MM-DD and the time as HH:MM and should return true for taken slots. Load your bookings first and check a Set, or call your API for the visible month.
- How are the time slots made?
- From hours.open to hours.close every hours.step minutes, leaving out any start time where the chosen service would end after closing. Change the step to 15, 30 or 60 minutes.
- Can I use it for restaurant tables?
- Yes. Pass services={[]} to skip the service step, set guests to the party sizes you accept and set evening hours. closedDays takes the weekdays you are closed, with 0 for Sunday.
- Does it handle time zones?
- Dates and times are the venue's local values as shown, sent as plain strings. Store them with your venue's time zone on the server.
- Is the calendar keyboard accessible?
- It is a grid: Tab moves into it, the arrow keys move by day and week (and change month at the edges), and Enter picks a day. Unavailable days are announced as unavailable, and time slots are radio buttons.