Choose Your Clinician

Who you see

Pick a clinician, or let us pick the soonest

Everyone here works across the same records, so choosing by availability costs you nothing in continuity.

No preference?

Taking the first available appointment usually gets you seen four days sooner, and your record follows you regardless of who you sit with.

Soft blue gradient backdrop
Portrait of Dr Amelia Frost

Dr Amelia Frost

Clinical lead

Next free Wednesday 09:00

Appointment45 or 60 minutes
SitesBristol and Southampton
Waiting6 days on median

Assessments and complex reviews

Fourteen years in practice, most of it in assessment work. Sees new referrals in the mornings and reviews after lunch.

Bramble Health and Harbour Practice

About this block

Choose Your ClinicianPRO

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.

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.

Upgrade to Pro

Pro blocks install through the shadcn CLI with your license key and ship their full source. Docs and live previews stay open to everyone, so you can read every block's details first.

Upgrade Now

Installation

Swap YOUR_EMAIL and YOUR_KEY for the email and license key on your account. Find your license key on your account page.

Radix flavor

bash
npx shadcn add "https://ui.beste.co/r/booking27?email=YOUR_EMAIL&license_key=YOUR_KEY"

Base UI flavor

bash
npx shadcn add "https://ui.beste.co/r-base/booking27?email=YOUR_EMAIL&license_key=YOUR_KEY"

This installs the block to components/beste/block/booking27.tsx, the card31 person piece it floats on the tile (installed to components/beste/piece/card31.tsx), and the badge23 and button21 components it uses for the eyebrow and the actions.

Quick start

The installed file exports booking27Demo alongside the block: the exact props behind the preview above. Spread it to get a working picker in one line.

tsx
import { Booking27, booking27Demo } from "@/components/beste/block/booking27";

export default function CliniciansPage() {
  return <Booking27 {...booking27Demo} />;
}

Then replace the demo with your own props. Written out, a trimmed setup looks like this:

tsx
import { Booking27 } from "@/components/beste/block/booking27";
import { Card31 } from "@/components/beste/piece/card31";

export default function CliniciansPage() {
  return (
    <Booking27
      badge={{ label: "Who you see" }}
      heading="Pick a clinician, or let us pick the soonest"
      description="Everyone here works across the same records."
      anyoneTitle="No preference?"
      anyoneBody="Taking the first available appointment usually gets you seen four days sooner."
      anyoneButton={{ label: "Book the soonest slot", href: "/booking/soonest" }}
      clinicians={[
        {
          name: "Dr Amelia Frost",
          role: "Clinical lead",
          avatar: { src: "/people/amelia.jpg", alt: "Portrait of Dr Amelia Frost" },
          next: "Next free Wednesday",
          focus: "Assessments and complex reviews",
          bio: "Fourteen years in practice, most of it in assessment work.",
          sites: "Bramble Health and Harbour Practice",
          media: (
            <Card31
              avatar={{ src: "/people/amelia.jpg", alt: "Portrait of Dr Amelia Frost" }}
              name="Dr Amelia Frost"
              role="Clinical lead"
              status="Next free Wednesday 09:00"
              availability="soon"
              rows={[{ label: "Appointment", value: "45 or 60 minutes" }]}
            />
          ),
        },
      ]}
      image={{ src: "/backdrops/blue.jpg", alt: "Soft blue gradient backdrop" }}
      button={{ label: "See their availability", href: "/booking/availability" }}
    />
  );
}

Props

PropTypeDefaultDescription
badge{ label: string }Eyebrow above the hairline rule, rendered through Badge23
headingstringSection heading in the left column of the header
descriptionstringSupporting paragraph, right-aligned from md up
anyoneTitlestringHeading in the no-preference panel
anyoneBodystringParagraph in that panel
anyoneButton{ label: string; href: string }Outline action for taking the soonest slot
cliniciansClinician[][]Selectable practitioners, the first starts selected
image{ src: string; alt: string }Backdrop shared by every clinician's tile
button{ label: string; href: string }Action under the selected clinician's detail
classNamestringExtra classes for the outer section
ts
type ActionLink = {
  label: string;
  href: string;
};

type Clinician = {
  name: string;
  role: string;
  avatar: { src: string; alt: string };
  next: string;
  focus: string;
  bio: string;
  sites: string;
  media: ReactNode;
};

Behavior notes

  • Each clinician carries their own media, so switching swaps the availability card entirely. The backdrop image is shared at block level, which keeps the tile steady while only the card changes.
  • Because avatar appears both on the list row and inside the piece, the demo passes the same object twice. They are separate props, so keeping them in sync is on you.
  • Selection is one piece of local useState holding an index, starting at 0. There is no onChange prop and no controlled mode.
  • Selected rows use a filled bg-muted surface rather than colour alone, and rows carry px-4 so the fill extends past the text.
  • next renders in the accent on every row, which makes availability the thing the eye lands on when comparing practitioners. That is the one accent use in the list.
  • The no-preference panel sits under the list rather than above it, so choosing a person is the default path and letting the system choose is the fallback.
  • The panel does not animate the swap. active.media is replaced outright, so a piece holding internal state resets when you switch away and back.
  • Rows are real button elements with aria-pressed and explicit cursor-pointer, since Tailwind v4 buttons default to cursor: default.

More Booking blocks

View all Booking
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

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

booking33

Session Picker

A booking chooser: a serif heading that settles in word by word and an intro, then a ruled list of session types on the left that swaps, with a soft blur, the muted detail card on the right showing a serif title, a description, a fact row and a sliding-marker pill.

FREE

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.

PRO

booking26

Minimal Service Picker

A quiet booking picker whose left column lists each service as a single hairline row carrying only its length and price, swapping a sticky panel that floats a live week strip above the chosen service's detail and its book action.

PRO

booking18

Cinema Seat Picker

Interactive seat selection grid for cinemas, theaters, and events. Row/column layout with an aisle gap, tier-based pricing (standard/premium/VIP), occupied seats, a live selection summary, and a legend. Includes screen indicator at the top.