Book an appointment
A React block (a whole screen) in Beamline's Clinic app.
A client books an appointment on the practice's own site: a service (length and price beside it), who gives it or anyone free, and where; a day with times open and that day's times in the client's own clock, the zone said above them and changeable, the practice's time said beside the chosen one; their details; then the practice's answer. Beside the steps (a strip on a phone) the appointment builds as a ticket that never lies about itself: a change that breaks a choice made later (a longer service, a practitioner who doesn't give it, a place it isn't offered) or a time someone else took meanwhile strikes that time, says why and offers the nearest times that fit, one tap each; a change that still fits keeps it. The button says what booking does at this practice (send a request, book, pay next) and the end says only what the practice answered: request sent and not booked yet, booked, or pay to hold the time. The appointment shows the practitioner's picture once chosen and the price large under its lines; a line still to choose is a dash. The chosen time is marked with the look's current-row tint, never the accent.
Use it for
- A practice, studio or salon's public booking page: clients choose a service, a person, a place and a time, and send their details.
- Any booking where a client may change an earlier choice after picking a time, or a time can be taken by someone else before they finish.
Not for
- Setting up services and hours (booking-setup).
- Booking from the desk with the day's calendar (appointment-book, team-calendar).
- Explaining why a time is closed to the owner (availability-layers).
Anatomy
- surface: one booking surface centred on the page (about 1090 px at rest, a booking page's height): the ticket on the start side, the steps beside it; on a phone the ticket over the steps
- ticket head: the practice whose page it is (its mark, name, what and where, and how it answers: Answers within a day, Reviews each request, Books instantly, Books once paid)
- steps: the title and the steps (Service, Day and time, Your details, Answer); a step reached can be gone back to
- service step: the services as cards in a grid (name, one line, price and length), then With (Anyone available or a practitioner who gives it) and Where (the clinic with its address, or a video call), each opening by its height when there is a choice
- day and time step: the month with only days that have times open; Times in <city, GMT±n> with the zone choice; the day's times in the client's clock by morning, afternoon and evening, the chosen one in the accent; a time a change broke stays in its place, struck
- details step: full name, email (where the answer comes), phone (starting on the client's country), a note; the button worded by the practice's policy (Send request, Book, Continue to payment); a request's hint
- ticket: Your appointment, a line per choice with Change: service with length and price, with whom (first free when anyone), where, when (day and time with the client's city, the practice's time beside it when the zones differ), you; a broken time struck with its reason and the nearest times that fit as buttons (with whom, when someone else), and Pick another day
- answer: the steps leave and the surface narrows to the ticket, which ends in the centre as the receipt: the practice's answer as its title with what it means, the lines, a reference, Pay when payment is needed, and Book another appointment
States
- nothing chosen (the ticket says to choose a service)
- times loading (shaped skeletons of a day's times)
- times failed (the reason and Try again)
- a day with no times (closed in the month), a month with none
- a time chosen (accent, and on the ticket with both zones)
- a change that still fits (the time is checked against the new times and kept: Checking <time> still works, then the time)
- a change that breaks the time: struck on the ticket and in the day's list, the reason (can't hold the new length, isn't free with the new practitioner, the practitioner doesn't give the new service, the service isn't offered at that place or on video), the nearest times that fit, one tap each
- a check that couldn't load (said, with Try again)
- taken meanwhile: the booking answers that someone else took it; the same struck line with that reason and the next free times; the details kept
- sending (the button shows progress), not sent (the reason; nothing booked; details kept)
- answer: request sent, not booked yet / booked / pay to hold this time (Pay), each with what it means; never a confirmation the practice didn't give; no step says done for a request
- narrow room: the ticket under the practice folds to one line over the steps and opens by its height (a broken time keeps it open); the calendar above the times
Keyboard
- Tab through the steps, the step and the ticket
- service, practitioner and place cards are radio groups: arrows move the choice
- the month is a grid: arrows by day and week, Page keys by month; closed days are skipped
- a time is a toggle button (pressed when chosen); a nearest time on the ticket is a button that takes it
- Change on each ticket line goes back to that step
- Enter in the details sends when the details are complete
Motion
What arrives fades in with a short rise. A step, a day's times and the steps at the answer leave by fading where they stood while the next arrives over them, taken away by a clock (never transitionend alone), and the room eases to the new height; choice groups and the phone's ticket open and close by their height; ticket lines glide on the shared flip when a line above them changes. The strike draws across a lost time, then the reason and the nearest times rise in turn. At the answer the surface narrows to the ticket, which rides to the centre. Reduced motion keeps the fades and places everything else at once. Nothing runs at rest.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
practice (required) | string | — | The practice's name, said in the answer ("Harbour Lane Therapy reviews requests…"). |
services (required) | BookableService[] | — | The services a client can book online (only these are offered). |
practitioners (required) | BookingPractitioner[] | — | |
places (required) | BookingPlace[] | — | |
currency (required) | string | — | ISO 4217 code prices are in ("GBP"). |
timezone (required) | string | — | The practice's IANA zone: said beside the client's when they differ. |
clientTimezone | string | — | The zone times are shown in at first: the client's own. Pass what you know of them (the browser's zone, a saved preference); the client can change it. Default: the practice's zone. |
zones | string[] | — | Zones offered in the time-zone choice, besides the client's and the practice's. |
loadTimes (required) | (query: TimesQuery, clientTimezone: string) => Promise<BookingSlot[]> | — | The bookable starts for the client's choices over a span of days in the client's zone. Return a promise; a rejection is said with its reason and Try again. Called again whenever a choice changes. |
onBook (required) | (request: BookingRequest) => Promise<BookingAnswer> | — | Sends the booking; resolve with the practice's answer (the end says only that). Resolve `taken` with the nearest free times when someone else took it meanwhile; reject only when nothing could be sent (the reason is said and the details are kept). |
policy | "confirm" | "pay" | "request" | — | What booking does at this practice, for the button's words: send a request the practice reviews, book at once, or go on to payment. The end still says what `onBook` answered. Default "request". |
timeFormat | "12h" | "24h" | — | How times of day are written. Default: the locale's own. |
today | string | — | Today (YYYY-MM-DD in the client's zone): no day before it is offered. Default: today. |
defaultService | string | — | The service chosen at first. |
onStepChange | ((step: number) => void) | — | Called with each step the client reaches (0 service … 3 answer). |
className | string | — | Classes on the documented visual root; no override by default. |
style | CSSProperties | — | Inline styles on the documented visual root; no overrides by default. |
ref | Ref<HTMLDivElement> | — | Receives the documented native target or imperative handle; omitted by default. |
phoneCountry | string | — | The country the phone field starts on (ISO code, "DE"): the client's, if you know it. |
practiceDetail | string | — | One line under the practice's name: what it is and where ("Physiotherapy · Marsh Road, London and video"). |
answersWithin | string | — | How soon the practice answers a request ("a day"), said under its name when it reviews requests. |
Built from
- stepper
- radio-cards
- calendar
- combobox
- phone-input
- input
- textarea
- alert
- skeleton
- button
- avatar
Dependencies
lucide-react
Import
import { ClientBooking } from "@beamline/client-booking";
Get it
Book an appointment is part of Beamline UI. Install the parts you need in your React app as compiled packages or editable source. Get Beamline · Connect your agent
More in Clinic
- Appointment book: The desk's day with the appointment editor beside it. The appointment being edited is a block on the day like any other, drawn in the accent while it is…
- Services and hours: A practice's services and the hours its practitioners can be booked, one relation seen from both ends. A service reads as values and changes on demand…
- Patient overview: One patient's record on a page. A search finds patients by name, chart number or birth date (recent patients when empty; same names told apart by birth…
- Patient chart: A clinic's chart for one client and their animals. The client's header (phone, email, contact preferences, the balance with what it means and as of when…
- Health questionnaire: A patient's medical history as a versioned questionnaire. Every question takes Yes, No or I don't know, and one not answered says so, never read as No; a…
- Case workspace: A patient's clinical cases and how cases work at the practice. A case shows its status, type, teeth, staff, location and start; its checklist counts…
- Care plan: A client's care plan composed beside what the client will see of it. Every field says who sees it (the care team only, or the client too) and the…
- Treatment plan: A patient's treatment plan in named phases. Each procedure shows its tooth, status and fee beside the patient's and the insurer's estimate (not known…
- Plan templates: Reusable treatment-plan templates. A template reads as words at rest and changes on demand: its name edits in place; the status its procedures start as…
- Plan acceptance: A treatment plan presented for acceptance, from both sides. The practice chooses the agreement (the account's default or this location's own) and how…
- Plan follow-up: The practice's follow-up lists, for the person who turns accepted treatment into booked chairs. Treatment plans lead with what's at stake: the value…
- Session notes and tasks: A session's note beside its follow-up tasks, each task tied to the exact words it came from: choose a task and its words light in the note or the…
- Note templates: A practitioner's note templates in one library with three ways in. My templates lists their own by kind, favourites first, each with when it was last…
- Probing chart: A periodontal probing chart. Six sites per tooth (three buccal, three lingual) across both arches as you face the patient, each depth in its cell and…
- Procedure picker: Procedures, conditions and bundles put on a patient's teeth from the chair. The mode (existing, planned, completed) is chosen before adding and each…
- Results notebook: A notebook entry's structured results. The entry's text above a bounded results table with typed columns: a sample link, numbers in their unit with their…
- Insurance claims: Insurance claims as a queue: every claim at first, in the order a person works them (rejected by the clearinghouse, denied by the payer, partly paid, not…
- Account ledger: A patient's account. All transactions or the ones needing attention, each dated with its type in a word, its amount and the running balance; entries that…
- Dispensing: Dispensing from the shelf by lot. A product is found with its stock and prices (consumables left out unless asked); the quantity is drawn across its…
- Record sharing: Records sent out of a clinic. Several visits' records and their documents (record, invoice, plan, lab result, image) are chosen separately, with how much…
- Client journal: A client's journal from both ends. The client's side is their home, built around their day: today's goals with how many are done and a mark each, done…