Skip to content
WingoUI
ComponentsTemplatesDocsPricingAI agentsBlogChangelogContact
Components
Buttons & Actions
ButtonButton GroupCopy ButtonDelete ButtonTheme ToggleToggleToggle Group
Inputs
Avatar UploadCalendarCheckboxColor PickerComboboxCountry SelectCron PickerCurrency InputDate PickerDate Range PickerDate Time PickerDuration PickerEmail InputEmoji PickerFile UploadFilter BuilderInputInput GroupListboxMasked InputMention InputMonth PickerMulti SelectNumber InputOTP InputPassword InputPhone InputRadio GroupRatingSearch InputSegmented ControlSelectSignature PadSliderSwitchTag InputTextareaTime PickerTimezone SelectTree Select
Forms
Address InputBooking WidgetCSV ImportFieldForm WizardInline EditInvoice line itemsRich Text EditorSchema Builder
Navigation
Back To TopBounce SidebarBreadcrumbCommand MenuGlobal SearchGooey NavHook SidebarNav MenuNav TabsPaginationProximity SidebarScroll ProgressSidebarStepsTable Of ContentsTabsTopbarUser MenuWorkspace Switcher
Overlays
Alert DialogContext MenuDialogDrawerDropdown MenuFamily DrawerHover CardPopoverShare DialogSheetShortcuts DialogTooltipTour
Feedback
AlertBannerCookie ConsentEmoji ReactionEmpty StateNotification BellNotification CenterProgressRoute ProgressSetup ChecklistSkeletonSpinnerToast
Data Display
Approval FlowAvatarBadgeCalendar ViewCode BlockComment ThreadContact cardCountdownDescription ListDiff ViewerFile ListFile managerFolderGanttJSON ViewerKbdLog ViewerMarkdownPresenceSchedulerTagTimelineTree View
Tables & Lists
Audit LogData TableDeal PipelineEditable GridKanbanListMembers tablePermissions MatrixTableTask ListVirtual List
Charts & Stats
Animated CounterArea chartBar chartDonut chartFunnel chartGaugeGitHub ActivityHeatmap calendarLeaderboardLine chartRadar chartRadial barSparklineStat CardTrackerTrend badge
Layout
AccordionApp ShellCardCollapsibleDetail LayoutEntity HeaderPage HeaderScroll AreaSeparatorSettings LayoutSplit ViewToolbar
Media
Audio PlayerCarouselCSV ViewerDOCX EditorDOCX ViewerExcel ViewerFile SystemImage compareImage CropperImage GalleryImage LightboxLocation MapPDF ViewerPowerPoint ViewerQR CodeStep PlayerVideo Player
AI Kit
Agent Status CardChat MessageChat ThreadChat WidgetConversation ListFluid OrbGrid RevealMatrix OrbModel PickerPrompt InputReasoning IndicatorRule BuilderSuggestion ChipsTool Call TimelineUsage MeterVoice InputWorkflow Canvas
Text & Effects
Background PatternGravity LettersMarqueeTerminalText AnimateText Rotate
Mobile
Action SheetBottom Tab BarFABHaptic ButtonHero HeaderInstall PromptLarge Title HeaderNotification BannerOnboarding CarouselPicker WheelPull To RefreshSlide To ConfirmSticky CTA BarSwipe DeckSwipeable Tabs
Commerce
Cart drawerCategory pickerCheckout stepsCoupon inputFavorite buttonFilter panelListing cardListing gridOrder trackerPricePrice rangePricing tableProduct galleryQuantity stepperReviewsSeller card
Marketing Sections
App Download SectionBlog Cards SectionCTA SectionFAQ SectionFeature GridFeature ShowcaseHero SectionIntegrations SectionLogo CloudMarketing FooterMarketing HeaderMarketing SectionNewsletter SectionPricing SectionStats SectionSteps SectionTeam SectionTestimonials SectionTimeline SectionVideo Section
Blocks
Admin Dashboard PageAdmin ShellAI Chat PageAPI Keys PageAutomation Builder PageCheckout PageCRM Contact PageCRM Pipeline PageError PagesInbox PageInvoice PageKPI DashboardListing Detail PageLogin PageMarketplace Home PageMarketplace Search PageMarketplace ShellMobile App HomeOnboarding FlowOrder History PagePost Listing WizardPricing PageProfile PageRegister PageSettings PageUsers Admin Page
Templates
About PageAcademy PageAccessibility PageAffiliate PageAgency PageAI Product PageAppointment Booking PageBlog PageBlog Post PageBug Bounty PageCareers PageChangelog PageCommunity PageCompare PageContact PageCustomer Story PageCustomers PageDemo Booking PageDevelopers PageDocs Home PageDownload PageEnterprise PageEvents PageExperts PageFAQ PageFeature PageGlossary PageHelp Article PageHelp Center PageHome Services PageImpact PageIntegration Detail PageIntegrations PageJob Detail PageLanding PageLaunch PageLegal PageManifesto PagePortfolio PagePress PageProduct Tour PagePromo PageReal Estate PageReferral PageResearch Report PageRestaurant PageRoadmap PageROI Calculator PageSecurity PageSolutions PageStartups PageStatus PageStorefront PageSwitch PageTemplate Gallery PageTravel PageWaitlist PageYear in Review Page
Hooks & Utilities
AI ChatChart kitCommerceDate utilsFile exportFile typesFiltersForm validationHapticsInvoicingMotion presetsNavigationNumber formatRelative timeRomanian locationsSpreadsheetText matchTonesUIProvideruseClipboarduseConsentuseControllableStateuseCooldownuseDebounceuseKeyboardInsetuseLocaleuseLongPressuseMediaControlsuseMediaQueryuseOverflowItemsusePersistedStateuseScrollEdgesuseScrollStateuseSelectionuseShortcutuseStickToBottom
GalleryTheme

Templates

Appointment Booking Page

Templates

Appointment Booking Page React template for Tailwind CSS v4

AI Product PageBlog Page
Live props
Behavior
slotStep30 min
bookingWindow60 days
locale
stickyBook
animateIn
Content
nextSlots3
nextSlotService
currency
Layout
bookingLayout
showServices
showTeam
showHours
showPayment
showFaq
showContact
showMap
header
footer
Appearance
hourCycle
tone
ctaTone
radius
background
backgroundColor
bandBackground
bandColor
Code
import { AppointmentBookingPage } from "@/components/templates/appointment-booking-page"

<AppointmentBookingPage />
  1. Home
  2. Templates
  3. Appointment Booking Page
Pro

Appointment Booking Page React template for Tailwind CSS v4

v1.0.0·Added in 1.14.0

A React appointment booking template for clinics, salons and coaches: next free times, a booking widget, services, team, hours and a map.

A one-page site for a service business built around booking. The hero shows whether the practice is open right now (with when it closes or opens next, in the business time zone) and the next free appointments for the first service; picking one glides down to the booking widget with that time and service filled in, on the details step. Book an appointment, the header Book button and See all times glide to the widget. The widget is the full booking flow: service and practitioner, a calendar with the free times (closed days disabled, times in the practice's zone with a switch), the details form and a confirmation with an .ics download. Every service row has its length and price and a Book button that opens the widget on the times for that service; every practitioner card lists specialties and languages, and Book a visit preselects that person. Opening hours mark today and the Open now status; on phones days with the same hours share a row. Insurance and payment notes, an FAQ accordion with a contact card, and the address, phone, email and directions next to a map (below the contact card on phones). On phones a Book bar with the next free time slides up from the bottom while the hero, the widget and the footer are out of view. Keyboard: every slot, Book button and link is reachable with Tab and activates with Enter or Space; the widget keeps its own arrow-key navigation. Reduced motion keeps everything still.

Appointment Booking Page is a Pro React template in the React website templates category, written in TypeScript for React 19 and Tailwind CSS v4. It installs as source with npx wingo-ui@latest add appointment-booking-page, together with Booking Widget, FAQ Section, Feature Grid, Marketing Section, Marketing Header and 11 more and the npm packages lucide-react and motion.

Built with

The sections this page is made of. In the full-screen preview, hold Alt to outline each one on the page.

  • FAQ Sectionfaq-section
  • Feature Gridfeature-grid
  • Marketing Sectionmarketing-section
  • Marketing Headermarketing-header
  • Marketing Footermarketing-footer

Add to a project

Requirements: React 19 and Tailwind CSS v4, in Next.js (App Router or Pages), Vite or React Router. Installation guide · Next.js setup · Vite setup

npx wingo-ui@latest add appointment-booking-page

Appointment Booking Page is part of Pro, with 298 more Pro items: $8 a month or $150 once. 14-day refund before you download any Pro item. See plans

Usage

Import AppointmentBookingPage from @/components/templates/appointment-booking-page.

// app/page.tsx
"use client"

import Link from "next/link"
import type { Booking, BookingSlotContext } from "@/components/blocks/booking-widget"
import { AppointmentBookingPage } from "@/components/templates/appointment-booking-page"

async function getTimeSlots(day: Date, { service, staff, timeZone }: BookingSlotContext) {
  const params = new URLSearchParams({ day: day.toDateString(), service: service.id, staff: staff?.id ?? "any", timeZone })
  const res = await fetch(`/api/availability?${params}`)
  return (await res.json()) as string[]
}

async function book(booking: Booking) {
  await fetch("/api/bookings", { method: "POST", body: JSON.stringify(booking) })
}

export default function HomeRoute() {
  return <AppointmentBookingPage linkComponent={Link} getTimeSlots={getTimeSlots} onBook={book} />
}

Props

  • businessdefault "APPOINTMENT_BUSINESS"
    AppointmentBusiness

    { name, tagline?, address, city, phone, email?, timeZone, hours, location?, directionsHref?, rating?, reviewCount?, hoursNote? }. hours is a list of { day (0 Sunday to 6 Saturday), open, close } wall times in timeZone; a day without an entry is closed, two entries make a lunch break. location { lat, lng } places the map pin.

  • servicesdefault "APPOINTMENT_SERVICES"
    AppointmentService[]

    BookingService plus category and priceFrom: { id, name, duration (minutes), price?, description?, category?, priceFrom?, disabled? }. A price of 0 shows Free; priceFrom shows from $180.

  • categoriesdefault "APPOINTMENT_SERVICE_CATEGORIES"
    AppointmentServiceCategory[]

    The service groups: { value, label, description? }. Services without a known category go under More services.

  • staffdefault "APPOINTMENT_STAFF"
    AppointmentStaff[]

    BookingStaff plus specialties, bio and languages: { id, name, role?, avatar?, services?, specialties?, bio?, languages?, disabled? }. services lists the ids a person offers (empty: all).

  • statsdefault "APPOINTMENT_STATS"
    AppointmentStat[]

    The numbers under the hero: { value, label }. [] hides them.

  • visitNotesdefault "APPOINTMENT_VISIT_NOTES"
    AppointmentVisitNote[]

    The Before your visit card next to the hours: { title, description }. [] hides the card.

  • paymentNotesdefault "APPOINTMENT_PAYMENT_NOTES"
    FeatureGridItem[]

    The insurance and payment cards: { icon, title, description }.

  • faqdefault "APPOINTMENT_FAQ"
    FaqItem[]

    The questions: { question, answer, category? }.

  • getTimeSlots
    (day: Date, context: BookingSlotContext) => (string | DateTimeSlot)[] | Promise<(string | DateTimeSlot)[]>

    The free times of a day as "HH:mm" wall times in context.timeZone, as in BookingWidget; it feeds both the widget and the next free times in the hero. Pass a stable function. Default: createHoursTimeSlots over business.hours, a few times taken per day.

  • slotStepdefault 30
    number

    Minutes between the default free times (without getTimeSlots).

  • onBook
    (booking: Booking) => void | Promise<unknown>

    Called by Confirm booking with { service, staff, start, end, timeZone, details, bookedAt }. A promise keeps the button loading; a rejection shows the error. Default: a pretend 900 ms request.

  • bookingWindowdefault 60
    number

    How many days ahead can be booked. 0 means no limit.

  • nextSlotsdefault 3
    number

    How many next free times the hero card lists (up to 6). 0 hides the card.

  • nextSlotServicedefault ""
    string

    The service id the hero looks up free times for. Empty: the first service.

  • bookingLayoutdefault "split"
    "split" | "stacked"

    The widget's layout: the summary column beside the steps, or a narrower card with the summary on top.

  • hourCycledefault "auto"
    "auto" | "h12" | "h23"

    12 or 24 hour times in the hours, the free times and the widget; auto follows the locale.

  • currencydefault "USD"
    string

    The ISO currency of the prices.

  • localedefault ""
    string

    Formats days, times, prices and numbers. Empty: the UIProvider locale, else en-US.

  • tonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    The booking widget, the service and payment icon tiles and the open FAQ item.

  • ctaTonedefault "neutral"
    "neutral" | "brand" | "success" | "warning" | "danger" | "info"

    The solid Book buttons in the header, the hero and the phone Book bar.

  • radiusdefault "lg"
    "none" | "sm" | "md" | "lg"

    Corners of the cards and the widget: 0, 12, 16 or 24px.

  • backgrounddefault "glow"
    "plain" | "soft" | "glow" | "aurora" | "grid" | "dots"

    The page's main background (PageBackdrop).

  • backgroundColordefault "oklch(0.62 0.14 275)"
    string

    The tint of the main background and its decoration.

  • bandBackgrounddefault "muted"
    "muted" | "tinted" | "gradient" | "dots"

    The look of every second section (the booking band first).

  • bandColordefault "oklch(0.62 0.14 275)"
    string

    The tint of tinted and gradient bands; the backgroundColor when equal.

  • showServicesdefault true
    boolean

    The services grouped by category, each with its length, price and a Book button.

  • showTeamdefault true
    boolean

    The practitioner cards with specialties, languages and Book a visit.

  • showHoursdefault true
    boolean

    The opening hours with today marked, the Open now status and the Before your visit card.

  • showPaymentdefault true
    boolean

    The insurance and payment notes (a FeatureGrid).

  • showFaqdefault true
    boolean

    The FAQ (a FaqSection with a contact card).

  • showContactdefault true
    boolean

    The address, phone, email, status and directions.

  • showMapdefault true
    boolean

    The map next to the contact card (below it on phones). Needs business.location.

  • stickyBookdefault true
    boolean

    Phones: a Book bar with the next free time pinned to the bottom while the hero, the widget and the footer are out of view.

  • headerdefault true
    boolean

    The sticky header with the section links, the phone number and Book.

  • footerdefault true
    boolean

    The footer with Care, Visit and Practice links.

  • headerProps
    Partial<MarketingHeaderProps>

    Anything for MarketingHeader (layout, variant, announcement...); wins over the page's own values.

  • footerProps
    Partial<MarketingFooterProps>

    Anything for MarketingFooter (variant, columns, socials, newsletter...).

  • bookingProps
    Partial<BookingWidgetProps>

    Anything for the embedded BookingWidget (requirePhone, showNotes, timeZones, rescheduleHref, labels...).

  • paymentProps
    Partial<FeatureGridProps>

    Anything for the insurance and payment FeatureGrid (layout, columns, card...).

  • faqProps
    Partial<FaqSectionProps>

    Anything for the FaqSection (layout, searchable, jsonLd...).

  • now
    Date | number

    What now means for the open status, today and the free times. Default: the clock.

  • animateIndefault true
    boolean

    The hero rises in once when the page mounts on the client; never during hydration, under reduced motion or in thumbnails.

  • linkComponent
    (props: LinkComponentProps) => ReactNode

    The router link for the header, footer and FAQ links (next/link in an app).

  • labels
    Partial<AppointmentBookingPageLabels>

    Every string of the page (DEFAULT_APPOINTMENT_BOOKING_PAGE_LABELS holds the English defaults), including the formatters for durations, prices, the open status and the free times.

  • className
    string

    Classes for the root.

  • classNames
    Partial<Record<AppointmentBookingPageSlot, string>>

    Classes for header, hero, nextSlots, booking, widget, services, service, team, member, hours, visit, payment, faq, contact, map, sticky and footer.

Parts

  • createHoursTimeSlots

    function

    Builds a getTimeSlots function from opening hours: a free time every step minutes inside each opening, shown in the visitor's zone, with a few taken per day and person. The page's default; use it to prototype before your availability API exists.

    • hours*
      AppointmentHoursRange[]

      The opening hours.

    • timeZone*
      string

      The IANA zone the hours are in.

    • options
      { step?: number; seed?: string }

      Minutes between times (default 30) and a seed for the taken ones.

  • getBusinessOpenStatus

    function

    Open or closed at a moment, with the closing time or the next opening: { open, today, closesAt?, opensAt?, opensIn?, opensDay? }. Read in the business time zone.

    • hours*
      AppointmentHoursRange[]

      The opening hours.

    • timeZone*
      string

      The IANA zone the hours are in.

    • now*
      Date | number

      The moment to check.

  • APPOINTMENT_BOOKING_PAGE_SAMPLE

    constant

    All the sample content in one object.

  • APPOINTMENT_BUSINESS

    constant

    Brightside Dental on South Lamar in Austin, open Monday to Saturday in Central Time.

  • APPOINTMENT_SERVICES

    constant

    Eight dental services from a new patient exam to a same-day crown, with lengths and prices.

  • APPOINTMENT_SERVICE_CATEGORIES

    constant

    Checkups and cleanings, Cosmetic, Fillings and crowns, Urgent care.

  • APPOINTMENT_STAFF

    constant

    Three dentists and a hygienist with specialties, bios, languages and the services they offer.

  • APPOINTMENT_STATS

    constant

    The three numbers under the hero.

  • APPOINTMENT_VISIT_NOTES

    constant

    Four Before your visit notes: forms, cards, parking, access.

  • APPOINTMENT_PAYMENT_NOTES

    constant

    Six insurance and payment cards with icons.

  • APPOINTMENT_FAQ

    constant

    Six questions about new patients, insurance, cancellations, emergencies, nerves and payment plans.

  • DEFAULT_APPOINTMENT_BOOKING_PAGE_LABELS

    constant

    The English strings.

  • AppointmentBookingPageProps

    type

    Props of AppointmentBookingPage, including the attributes of the root element.

  • AppointmentBookingPageLabels

    type

    Every string of the page.

  • AppointmentBookingPageRadius

    type

    "none" | "sm" | "md" | "lg".

  • AppointmentBookingPageSlot

    type

    The keys of classNames.

  • AppointmentBusiness

    type

    The practice: name, address, phone, time zone, hours and map position.

  • AppointmentHoursRange

    type

    { day, open, close }: one opening of a weekday, as "HH:mm".

  • AppointmentWeekday

    type

    0 (Sunday) to 6 (Saturday).

  • AppointmentService

    type

    A bookable service with its category.

  • AppointmentServiceCategory

    type

    { value, label, description? }.

  • AppointmentStaff

    type

    A practitioner with specialties, bio and languages.

  • AppointmentStat

    type

    { value, label }.

  • AppointmentVisitNote

    type

    { title, description }.

  • AppointmentSlot

    type

    A free start the hero lists: { start, day, time }.

  • AppointmentOpenStatus

    type

    What getBusinessOpenStatus returns.

Examples

Open

A hair salon

The same page for a salon in New York: other business, hours (closed Mondays), services, categories and stylists, with brand Book buttons.

Open

Brand accents

tone and ctaTone brand on an aurora page with tinted bands: the widget, icon tiles and Book buttons turn orange.

Open

Closed right now

now is a Sunday evening: the status reads Closed now, Opens tomorrow at 8:00 AM, and the first free times are on Monday.

Open

A lean booking page

Only the hero, the widget (stacked), the hours and the contact card, with square-ish corners and a dotted background.

Open

A slow availability API

getTimeSlots answers after 1.2s: the hero card shows skeleton rows until the first free times arrive.

Dependencies

lucide-reactmotionbooking-widgetfaq-sectionfeature-gridmarketing-sectionmarketing-headermarketing-footerlocation-mapdate-time-pickeravatarbadgebuttonnavigationrelative-timemotiontonesui-config

Files

  • components/templates/appointment-booking-page.tsx
  • components/templates/appointment-booking-page-data.ts

FAQ

Is the React Appointment Booking Page template free?

The preview, props and docs are free; copying the source needs a Pro plan. See plans.

How do I install Appointment Booking Page?

Run npx wingo-ui@latest add appointment-booking-page. It also adds the Wingo UI items it builds on (Booking Widget, FAQ Section, Feature Grid, Marketing Section, Marketing Header and 11 more) and the npm packages lucide-react and motion. With shadcn, add the @wingo-ui registry with your API key, then run npx shadcn@latest add @wingo-ui/appointment-booking-page.

How does Appointment Booking Page behave on phones?

Opening hours mark today and the Open now status; on phones days with the same hours share a row. Insurance and payment notes, an FAQ accordion with a contact card, and the address, phone, email and directions next to a map (below the contact card on phones).

See also

Booking WidgetDemo Booking PageLocation MapFAQ SectionReal Estate Page
PreviousAI Product PageNext Blog Page