Booking pillPro
One pill that reshapes through party size, date, time, and a ticket.
Live · keyboard ready

Olea
Tuesday to Sunday from 5 PM
- Venue or service pages where booking a table or slot is the one action people came for.
- Mobile-first flows that walk through party size, date, time, and confirm in one surface.
- Use date-picker and time-picker inside a regular form for multi-field checkouts.
- Use stepper or multi-step-form for longer flows with many fields.
- Use calendar when people need to see a whole month.
Installation
Pro source and install commands unlock with a Pro plan.
example.tsx
import { BookingPill, type Booking } from "@/registry/components/booking-pill/booking-pill"; export function ReserveBar({ today, book }: { today: string; book: (booking: Booking) => Promise<void> }) { return ( <BookingPill venue="Osteria Nove" venueDetail="12 Harbour Street" startDate={today} hourCycle={24} isAvailable={(date, time, party) => !(party > 6 && time > "20:00")} onConfirm={book} /> );}BookingPill
One floating pill that reshapes itself through a booking flow: party size, a draggable date strip, a time grid, a ticket to confirm, and a booked state.
PropTypeDefaultDescription
venueRequiredstring–Venue name printed on the ticket.venueDetailstring–Second ticket line, such as the address.startDateRequiredstring–First day on the strip as an ISO date. Pass it from data so server and client agree.daysnumber21Days on the strip.timesstring[]["17:00", "17:30", … "22:30"]Seating times as "HH:MM", in order, shown four to a row. The default runs every half hour from 17:00 to 22:30.isAvailable(date: string, time: string, partySize: number) => boolean–Whether a time is free. Everything is free by default.preferredTimestring"19:30"Preselected when free, otherwise the nearest free time, as "HH:MM".minPartySizenumber1Smallest party.maxPartySizenumber12Largest party.defaultPartySizenumber2Starting party size.onConfirm(booking: { date: string; time: string; partySize: number }) => Promise<void> | void–Books the table. Resolve to show the booked state, reject to keep the ticket open with an error. Defaults to a short simulated wait.onStepChange(step: "start" | "party" | "date" | "time" | "review" | "booked") => void–Called on every step, for example to let the page recede while the pill is open.hourCycle12 | 2412Clock used for displayed times, such as 7:30 PM or 19:30. times, preferredTime, and onConfirm always use "HH:MM".labelstring"Book a table"Label of the closed pill.classNamestring–Class on the root element.- Arrow keys
- Move a day on the date strip, or between free times in the grid.
- Page UporPage Down
- Move a week on the date strip.
- HomeorEnd
- First or last day, or first or last free time.
- Enter
- Confirm the date on the strip and continue.
- Escape
- Go back one step.
- The date strip is a role="slider" with a spoken aria-valuetext; times are a role="radiogroup" with unavailable times marked aria-disabled.
- Every round icon button has an aria-label (Back, Fewer guests, Next, choose a date).
- Step changes are announced in a polite live region, and booking errors use role="alert".
- The pill's shape springs to fit each step while content slides in a beat later in the direction of travel.
- The date strip follows drags 1:1, rubber-bands at the ends, and flicks glide to a day; party count digits roll.
- Reduced motion jumps the strip, drops slides and blurs, and swaps faces with fades.
- The root is a container; each step's face is capped at the container width minus 24px, up to 340 to 420px.
- The date strip drags horizontally with touch-action pan-y, so vertical page scroll still works on touch.
- The pill uses a 24px backdrop blur; the date strip renders every day in days, 21 by default.
- ResizeObservers track each face for the shape spring, and only the current step is mounted.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Use on a venue or service page where booking is the one action people came for. Use date-picker and time-picker in a regular form for multi-field checkouts.
- Anchor it to the bottom of its container, pass startDate from the server, and wire isAvailable and onConfirm to your backend. Set hourCycle for display only; data stays in "HH:MM".
The full library index for assistants is at /llms.txt.