Booking Card
BookingCard is a compound component. It holds the chosen day and slot; BookingCard.Days, BookingCard.Slots, BookingCard.Submit and BookingCard.Confirmation go inside it in whatever layout the panel needs. It draws no surface of its own, so it sits as comfortably in a plain bordered card as in a glass slab from Glass Panel — the Book Appointment section is the same card on a full page.In a card
Pick a day and a time, press Book — the button stays busy while your onBook promise runs, then the check draws itself and the details rise in.
BookingCard- holds the chosen day and slot. Put
BookingCard.Days,BookingCard.Slots,BookingCard.SubmitandBookingCard.Confirmationinside it in any layout; the confirmation covers theBookingCardit sits in — so give theBookingCardthe panel's padding (heading included) and the cover reaches the panel's edges and corners. - Return a promise from
onBook - and the button stays busy until it settles — resolve to show the confirmation, throw to drop back to the form.
unavailable(day) => day.getDay() === 0- on
BookingCard.Daysstrikes out days with nothing free. Sundays here; feed it your real availability. - The Book button, the check and every focus ring take
--primary - so the card follows your theme — pick a colour above to see it. Selected days and slots stay a neutral ink that reads on glass or solid.
- The arrows page
BookingCard.Days - a week at a time, up to
horizondays out (90 by default). Days start today, so the previous arrow is disabled on the first page — nobody can book into the past.
Installation
New project? Follow the installation guide to set up Tailwind CSS, shadcn, the cn helper and lucide-react, register the @algorize-ui registry once, then copy your styles from the Themes page.
Install Booking Card
components/ is written into your project. Copy any snippet from a Usage tab above and it runs.
Install dependencies
Step 1 installs this for you. Run it yourself only if you are adding Booking Card to an existing project by hand. The cn helper and lucide-react are not listed — the installation guide covers them once for every component.
glass-panel is a component, not a package — the shadcn CLI installs it as source files.
Examples
In a glass slab
The same card inside a GlassPanel from Glass Panel. Nothing inside the card changes — it is surface-neutral by design.
- Wrap it in a
GlassPanel - and the card takes the panel's corners: its root is
rounded-[inherit], so the confirmation's cover matches whatever shape it sits in.
Liquid glass
The booking card rendered inside a liquid-glass refraction surface.
- Set variant to
liquid-glass - on
GlassBackdropto render realistic SVG fluid refraction with pure white glass elements.
Features
One state, any layout
Days, slots and the button share one context. Stack them, put them side by side, split them across panels — the card does not care.
A confirmation that shows what happened
When onBook resolves, a check draws itself over the form and the day, time and place rise in beneath it. Book another clears it. It holds still under prefers-reduced-motion.
Keyboard and screen reader ready
Days and slots are radio groups with full date names; taken slots and closed days are disabled, not hidden; the busy button carries aria-busy and the confirmation is a status region.
Honest about today
The default days are built on the client, so a server render never guesses the visitor's date. They start today and page forward a week at a time — the previous arrow never reaches into the past. Pass your own days array to offer a different range.
Props Reference
BookingCard
| Prop | Type | Default | Description |
|---|---|---|---|
onBook | (booking: { day: Date; slot: string }) => void | Promise<void> | — | Called on confirm. Return a promise to hold the busy state; a rejection returns to the form. |
className | string | — | Layout of the parts inside. The confirmation is positioned against this element. |
BookingCard.Days
| Prop | Type | Default | Description |
|---|---|---|---|
days | Date[] | today → horizon | Days on offer, in order, paged count at a time with the previous/next arrows. The default is built on the client so the server never guesses today, and it starts today — there is no paging back into the past. |
count | number | 7 | Days shown per page. |
horizon | number | 90 | How far ahead the default days run, in days from today. Ignored when days is given. |
unavailable | (day: Date) => boolean | — | Days with nothing free — shown struck through, not selectable. |
BookingCard.Slots
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Group title, e.g. "Morning". |
slots | { label: string; taken?: boolean }[] | — | Times in the group. Disabled until a day is chosen; taken slots are shown struck through. |
BookingCard.Submit
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | "Book now" | Button text. Once a day and slot are chosen it reads back the choice, e.g. Book now, Wed 25 at 9:00 AM. |
BookingCard.Confirmation
| Prop | Type | Default | Description |
|---|---|---|---|
withName | string | — | Who the appointment is with. |
place | string | — | Where, appended after the name. |