Booking.com-style social proof ticker with rotating messages: live viewers, recent bookings, scarcity alerts, and location-based activity. Animated transitions, urgency indicators, and trust signals that boost conversion.
A Booking.com-style social proof panel that rotates a single animated ticker message (viewers, recent bookings, scarcity, location, or trending, each keyed to its own icon and color) on a timed interval with clickable dot navigation, stacked beneath a live "Live Activity" header and above a column of optional conversion cards: a per-second countdown, a recent-booking toast, a struck-through price comparison, a high-demand strip, an urgency alert, a three-column trust strip, a viewers avatar stack, a reviews summary, and a 24-hour hourly-bookings bar chart with per-bar tooltips.
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.
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
npx shadcn add "https://ui.beste.co/r/booking13?email=YOUR_EMAIL&license_key=YOUR_KEY"Base UI flavor
npx shadcn add "https://ui.beste.co/r-base/booking13?email=YOUR_EMAIL&license_key=YOUR_KEY"This installs the block to components/beste/block/booking13.tsx, plus the avatar, badge, and tooltip shadcn/ui primitives it uses for the viewer/review avatar stacks, the section and price badges, and the hourly heat-chart tooltips.
The installed file exports booking13Demo alongside the block: the exact props behind the preview above. Spread it to get a working social proof bar in one line.
import { Booking13, booking13Demo } from "@/components/beste/block/booking13";
export default function Page() {
return <Booking13 {...booking13Demo} />;
}Then replace the demo with your own props. Written out, a trimmed setup looks like this:
import { Booking13 } from "@/components/beste/block/booking13";
export default function Page() {
return (
<Booking13
badge={{ label: "Social proof", variant: "secondary" }}
heading="Show <strong>live activity</strong>"
interval={4000}
messages={[
{ type: "viewers", text: "{highlight} people are looking right now", highlight: "14" },
{ type: "scarcity", text: "Only {highlight}", highlight: "2 slots left", time: "for your date" },
]}
priceComparisonVariant={{ currency: "$", originalPrice: 180, currentPrice: 129, saveLabel: "Save" }}
countdownVariant={{ label: "Offer ends in", endsAt: "2026-07-13T09:00:00Z", expiredLabel: "Offer ended" }}
labels={{ liveActivityLabel: "Live Activity", verifiedDataLabel: "Verified data" }}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
badge | { label: string; variant?: "default" | "secondary" | "outline" } | – | Section eyebrow badge above the heading |
heading | string | – | Section heading, supports inline <strong> |
description | string | – | Optional subheading paragraph under the heading |
messages | ProofMessage[] | [] | Rotating ticker messages cycled in the live panel |
interval | number | 4000 | Milliseconds between automatic ticker advances |
highDemandVariant | HighDemandVariant | – | Flame "in high demand" card |
urgencyVariant | UrgencyVariant | – | Rose urgency strip with a badge |
viewersVariant | ViewersVariant | – | Viewers count row with an avatar stack |
countdownVariant | CountdownVariant | – | Per-second countdown card |
recentBookingToast | RecentBookingToast | – | Single "just booked" toast card |
priceComparisonVariant | PriceComparisonVariant | – | Struck-through price with a computed savings badge |
trustStripVariant | TrustStripVariant | – | Three-column icon+label trust strip |
reviewsVariant | ReviewsVariant | – | Star rating and review-count summary |
heatVariant | HeatVariant | – | 24-hour hourly-bookings bar chart |
labels | Booking13Labels | {} | Header labels (liveActivityLabel, verifiedDataLabel) |
className | string | – | Extra classes for the outer <section> |
type ProofType = "viewers" | "recent" | "scarcity" | "location" | "trending";
type ProofMessage = {
type: ProofType;
text: string; // "{highlight}" placeholder is swapped for the highlight span
highlight?: string;
time?: string;
};
type HighDemandVariant = { title: string; description: string };
type UrgencyVariant = { text: string; badgeLabel: string };
type ViewersVariant = {
countLabel: string;
suffix: string;
avatars: string[];
extraCount: number;
};
type CountdownVariant = {
label: string;
endsAt: string; // ISO date string
expiredLabel: string;
};
type RecentBookingToast = {
name: string;
location: string;
avatar: string;
actionLabel: string;
timeAgo: string;
};
type PriceComparisonVariant = {
currency: string;
originalPrice: number;
currentPrice: number;
saveLabel: string;
};
type TrustSignal = { icon: LucideIcon; label: string };
type TrustStripVariant = { signals: TrustSignal[] };
type ReviewsVariant = {
rating: number;
count: number;
suffixTemplate: string; // "{count}" is replaced with count.toLocaleString()
avatars: string[];
};
type HeatVariant = {
label: string;
subtitle: string;
hourlyBookings: number[];
currentHour: number;
tooltipTemplate: string; // "{hour}" and "{count}" placeholders
};
type Booking13Labels = {
liveActivityLabel?: string;
verifiedDataLabel?: string;
};messages.length > 1: a setInterval(advance, interval) fades the current message out for 400ms, then bumps currentIndex to (prev + 1) % messages.length and fades back in. With one or zero messages no timer is set.useState and is never lifted out; there is no onChange callback, so a parent cannot observe or drive which proof message is showing. The dot buttons under the panel just set that same internal index.typeConfig map keyed by type; only scarcity (rose) and location (emerald) diverge from text-primary, so unlisted types would render nothing since config would be undefined.renderMessage splits text on the literal token {highlight} and injects a bold colored span; if highlight is omitted the raw text is shown verbatim and the token, if present, stays as literal text.remaining starts null (rendering an em-dash placeholder) and is only computed in useEffect after mount, ticking every second. It shows expiredLabel once endsAt passes, and prepends a Nd day segment only when days remain.heading is injected with dangerouslySetInnerHTML, so any inline <strong> (styled bold/primary) renders as markup rather than escaped text; pass trusted strings only.max((count / max) * 100, 6)% height so empty hours still show a 6% stub, highlights the bar at currentHour in primary, and exposes each hour through both an aria-label and a Radix Tooltip built from tooltipTemplate.trustStripVariant/heatVariant additionally require a non-empty array); passing none leaves just the live ticker panel. The whole header block (badge/heading/description) is likewise skipped when all three are absent.booking15
Post-booking success screen with animated check icon, confirmation number, booking summary (service, date/time, location, total), scannable QR code ticket, action buttons (calendar, receipt, directions), and email confirmation note.
booking12
Airbnb/Booking.com-style search bar with location autocomplete, date range picker, guest counter dropdown, and search CTA. Responsive — inline on desktop, stacked on mobile. The universal booking hero section.
booking19
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.
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.
booking23
Booking cancellation screen with the original booking summary, cancellation reason picker (radio list with optional notes), live refund breakdown based on cancellation policy, confirmation checkbox, and destructive cancel action.
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.