Appointment Intake MatchFREE

Three intake questions that land on a real appointment type instead of a drop-down: the answers pick a route with its length, its facts, and the clinician you will sit with, and the image tile beside them swaps its floated availability card to match.

Booking29: Appointment Intake Match

Three intake questions that land on a real appointment type instead of a drop-down. The answers pick a route with its length, its facts, and the clinician you will sit with, and the image tile beside them swaps its floated availability card to match.

Free block

This block is free. No license or account is required: install it with the CLI and use it in unlimited projects.

Installation

Radix flavor

bash
npx shadcn add "https://ui.beste.co/r/booking29"

Base UI flavor

bash
npx shadcn add "https://ui.beste.co/r-base/booking29"

That installs the block file, the badge23 eyebrow and button21 action button it is built from, the card31 piece it floats over the image, and the questionnaire primitive.

Quick start

tsx
import { Booking29, booking29Demo } from "@/components/beste/block/booking29";

export default function Page() {
  return <Booking29 {...booking29Demo} />;
}
tsx
import { Booking29 } from "@/components/beste/block/booking29";
import { Card31 } from "@/components/beste/piece/card31";

export default function Page() {
  return (
    <Booking29
      badge={{ label: "Before you book" }}
      heading="Three questions decide the appointment, not a drop-down"
      description="Every combination lands on a real appointment type."
      shortcuts="numbers"
      questions={[
        {
          name: "reason",
          title: "What brings you in?",
          choices: [
            { value: "assessment", label: "Something new" },
            { value: "review", label: "A follow-up" },
          ],
        },
        {
          name: "history",
          title: "Have you been seen here before?",
          choices: [
            { value: "new", label: "First time" },
            { value: "returning", label: "I am already registered" },
          ],
        },
      ]}
      routes={[
        {
          // both answers have to fit, so this sits above the looser route
          match: { reason: "assessment", history: "new" },
          title: "First assessment, 60 minutes",
          summary: "A full first appointment with the assessment lead.",
          facts: [
            { label: "With", value: "Dr Amelia Frost" },
            { label: "Length", value: "60 minutes" },
          ],
          media: <Card31 name="Dr Amelia Frost" role="Assessment lead" availability="soon" />,
        },
        {
          // no match: the catch-all, and it has to be last
          title: "Advice call, 15 minutes",
          summary: "A short call with whoever is on duty.",
          media: <Card31 name="Sara Okonjo" role="Duty practitioner" availability="free" />,
        },
      ]}
      image={{ src: "https://images.unsplash.com/photo-1750918619871-dc74c9a57394", alt: "Backdrop" }}
      media={<Card31 name="Sara Okonjo" role="Duty practitioner" availability="free" />}
      waitingBody="Whoever you end up with, the notes follow you."
      button={{ label: "Choose a time", href: "https://beste.co" }}
    />
  );
}

Props

PropTypeDefaultDescription
badgeBadgeEyebrow above the rule, rendered with Badge23.
headingstringSection heading.
descriptionstringLead paragraph, set opposite the heading.
questionsIntakeQuestion[][]The intake questions, in the order they are asked.
shortcuts"letters" | "numbers"Prints a shortcut on every choice of the active question.
routesRoute[][]Checked in order; the first one whose match fits wins.
imageTileImageBackdrop behind the floated piece.
mediaReactNodePiece shown on the tile before anything is answered.
waitingBodystringLine under the tile, kept in both states.
buttonActionLinkButton21 beside the matched appointment.
labelsBooking29Labels{}Overrides for the navigation buttons and the two panel headings.
classNamestringMerged onto the section element.
ts
type Badge = { label: string };
type ActionLink = { label: string; href: string };
type TileImage = { src: string; alt: string };
type Fact = { label: string; value: string };

type IntakeQuestion = {
  name: string;
  title: string;
  description?: string;
  choices?: IntakeChoice[];
};

type IntakeChoice = { value: string; label: string; description?: string };

type Route = {
  match?: Record<string, string>;
  title: string;
  summary: string;
  facts?: Fact[];
  media?: ReactNode;
};

type Booking29Labels = {
  previous?: string;
  next?: string;
  submit?: string;
  restart?: string;
  matchTitle?: string;
  waitingTitle?: string;
};

Behavior notes

More Booking blocks

View all Booking
PRO

booking27

Choose Your Clinician

A clinician picker whose hairline list of practitioners, each showing their next opening, swaps an image tile floating a live availability card alongside their focus, background, and sites.

PRO

booking28

Waiting List Capture

A no-availability state that answers with three hairline figures and a numbered explanation of how offers are made, beside a sticky square tile floating a live panel of the waiting list itself and an urgent fallback.

PRO

booking24

Service And Slot Picker

An interactive appointment picker: a hairline panel pairing a selectable service list with a scrollable day strip and a time slot grid that marks unavailable times, beside a full-height provider photo with a gradient name card, closing on a live summary bar and confirm action.

FREE

booking4

Service Selector

Service selection grid with category filter tabs, service cards showing icon, name, description, duration, price, and selected state. Ideal for spa, salon, clinic, and fitness booking flows.

FREE

booking5

Provider Picker

Staff/provider selection cards with avatar, name, specialty, star rating, review count, availability badge, experience years, and selected state. Grid layout with "Any Provider" option.

PRO

booking19

Multi-step Booking Wizard

Stepper-based booking flow with numbered progress dots, animated progress bar, and four steps: service selection, schedule, contact details, and review. Back/Next navigation, per-step validation, and a live summary.