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.
Step-one service picker for a booking flow: a pill-style category filter narrows a scrollable list of service rows, each showing an icon, name, optional badge, duration, and price, with a sticky footer summarizing the current pick and a "Next Step" button.
Free block
This block is free. No license or account is required: install it with the CLI and use it in unlimited projects.
Radix flavor
npx shadcn add "https://ui.beste.co/r/booking4"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/booking4"This installs the block to components/beste/block/booking4.tsx, plus the badge and button shadcn/ui primitives it uses for the service badges and footer button.
The installed file exports booking4Demo alongside the block: the exact props behind the preview above. Spread it to get a working service selector in one line.
import { Booking4, booking4Demo } from "@/components/beste/block/booking4";
export default function BookingStep1Page() {
return <Booking4 {...booking4Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Hand, Scissors, Sparkles } from "lucide-react";
import { Booking4 } from "@/components/beste/block/booking4";
export default function BookingStep1Page() {
return (
<Booking4
badge={{ label: "Step 1 of 3", variant: "secondary" }}
heading="Choose your <strong>service</strong>"
description="Pick the treatment that suits you best."
services={[
{
name: "Swedish Massage",
description: "Gentle full-body massage for relaxation",
duration: "60 min",
price: "$89",
category: "Massage",
icon: Hand,
badge: "Popular",
},
{
name: "Hot Stone Therapy",
description: "Heated stones for deep relaxation",
duration: "75 min",
price: "$140",
category: "Massage",
icon: Sparkles,
},
{
name: "Haircut & Styling",
description: "Precision cut with wash and blow-dry",
duration: "45 min",
price: "$65",
category: "Hair",
icon: Scissors,
},
]}
labels={{ allCategory: "All", noSelection: "No service selected", nextButton: "Next Step" }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
badge | { label: string; variant?: "default" | "secondary" | "outline" } | – | Section eyebrow badge |
heading | string | – | Section heading, supports inline <strong> |
description | string | – | Section intro text |
services | Service[] | [] | Rows rendered in the scrollable list |
labels | Booking4Labels | {} | UI copy: category filter label, empty-state text, footer button text |
className | string | – | Extra classes for the outer <section> |
type Service = {
name: string;
description: string;
duration: string;
price: string;
category: string;
icon: LucideIcon;
badge?: string;
};
type Booking4Labels = {
allCategory?: string;
noSelection?: string;
nextButton?: string;
};Tabs component. They're built from [allCategory, ...new Set(services.map(s => s.category))] and only render when there are more than two categories in that list (in effect, more than one real category besides "All").service.name as a string key, not an index or id, so two services sharing the same name would both be treated as selected together.heading supports inline <strong> markup rendered via dangerouslySetInnerHTML (the demo uses "Choose your <strong>service</strong>").console.log("Selected service:", selected), it does not navigate or submit anywhere, so wiring an actual next step is left to the integrator.max-h-[480px], keeping the category tabs and the footer summary always in view.booking5
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.
booking18
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.
booking16
Residential cleaning service booking with service type tabs (standard/deep/move-out), bedroom/bathroom selectors, recurring frequency pills, add-ons checklist, date picker, estimated duration, and price breakdown footer.
booking1
Split-panel booking interface with interactive monthly calendar on the left and time slot grid on the right. Features today highlight, disabled dates, selected state, morning/afternoon grouping, and booking summary footer.
booking3
Upcoming and past appointments list grouped by date, with service name, provider avatar, time, duration, status badges (confirmed/pending/cancelled), and reschedule/cancel action buttons.
booking20
Vehicle rental flow with pickup and return location fields, date range picker, car class grid (compact/suv/luxury) with image and specs, insurance tier selector, optional add-ons, and live price breakdown.