014
AI ready Refreshed

Appointment Booking Template

£29 View live demo or the whole Vault, £79.20

Includes the original v1 design as a separate download.

Six-page site for any business where the customer books a person by name. Pull a colour tab down the hero and the page switches to that person, their colour following them through the team, their profile and a booking flow that floods with it. The demo is a three-chair barber shop in Deptford.

ScrollTriggerFlipDraggable Lenis intermediate
10 more details
InertiaPlugin dragmomentumflipclip-pathscroll-revealstaggerview-transitionskeyboard-navigationprogressive-enhancement

Updated

About this template

A booking-first site in six plain pages: home, booking, the team, one worked profile page, prices and a visit page with a real map. It suits any business where people are booked by name: barbers and salons first, but also tattoo studios, nail and brow bars, physios and treatment rooms, tutors and trainers.

Read the full template overview

The design rests on one idea: every person owns a colour. Their portrait is photographed against it, the section behind the portrait is painted the same colour so photo and page meet without an edge, and that colour follows them through the team page, their profile, the booking stage and the ticket. Headlines are a heavy extended italic in capitals on whole-section grounds that change colour as you scroll.

The home page opens on the backdrop pull: three paper tabs hang from a rail, one per person, and pulling one down unrolls that colour over the page with a framed photo of that person at work, so any ordinary staff photo works there. The booking page is the product's working centre: choosing a person floods the page with their colour, then a service and a time are picked against that person's own diary while a ticket keeps the running total. It is a front-end flow with no backend, ready to point at a booking service.

Re-pointing it is a copy pass, new portraits on the new colours and five colour tokens. The demo is Garnett & Sons, a second-generation barber shop on Deptford High Street, with bundled photography.

Appointment Booking Template - website template preview

What's included

11 items
  • Six complete pages: home, book, barbers, a barber profile, prices and visit, with shared nav and footer and plain page loads plus a CSS view-transition crossfade
  • Backdrop pull hero: drag a colour tab down and that barber's colour unrolls over the page with a framed photo of them at work; past a third it completes, otherwise it rolls back, and a tap, Enter or Space plays the whole unroll
  • A colour per person carried through every page: portrait backdrops, section grounds, booking stage, ticket and footer booking blocks all read from one token per person
  • Three-step booking page: choosing a barber floods the page with their colour, services they do not offer are struck through, taken times come from their own diary, and a ticket keeps the total and end time
  • Deep links into booking: book.html?barber=lewis lands on step two in Lewis's colour, and &service=skin-fade ticks the service
  • Cut wall on the home page filtered by barber with colour chips, animated with Flip
  • Profile page built to duplicate per person: full-bleed portrait, a turn-the-head viewer showing one cut from the front, side and back, a draggable cut roll with momentum, their price list and their week
  • Prices page set as full-width colour bands per service group, plus a build-a-visit tool that totals a cut and extras, shows chair time and carries the cut into booking
  • Visit page with a real MapLibre street map on OpenFreeMap tiles, two real walking routes that draw on selection, and opening hours with an open-now line
  • Every interaction works by keyboard and touch, the booking flow reads as plain lists with a phone number without JavaScript, and reduced motion keeps every feature with the motion removed
  • Bundled portraits and shop photography as art-directed WebP files, with the backdrop colours sampled into the colour tokens

Perfect for

6 use cases
  • Barber shops, hair salons and grooming studios
  • Any appointment business where the customer picks a person, a service and a time
  • Tattoo and piercing studios that book by artist
  • Nail bars, brow and lash studios and beauty rooms with a small team
  • Physios, massage and treatment rooms that book by practitioner
  • Tutors, personal trainers and coaches who are booked by name

How it works

5 sections

A colour per person

Five tokens hold the whole palette: one colour per person plus a light and a dark neutral. Any element carrying a data-tone attribute paints its ground and text from that person's colour, including the right text colour and dim strength for that ground, so a block moved from one person's section to another stays legible. The portrait backdrops were sampled into the tokens so photographs meet their sections without a seam.

The backdrop pull

Each person in the hero is a layer on their own colour holding a framed photo of them at work. Dragging a tab reveals the incoming layer from the top with a clip-path that follows the pointer, a paper edge riding on the reveal line, and the nav and headline switching colour as the paper passes them. Release past a third completes the unroll; anything less rolls it back. Without JavaScript the first person shows and the tabs are links to the team page.

The booking flow

Three native radio groups are the entire data model. The ticket is derived from the checked inputs every time, the end time is the slot plus the service's minutes, each time slot lists the people it is taken for and each service lists the people who do it, so changing person re-reads both and releases anything no longer possible. Focus moves to each step and a live region announces it.

Profile, prices and map

The turn-the-head viewer is three matched photographs switched by a horizontal drag or three radio buttons. The cut roll uses Draggable with inertia, with arrow buttons and keys, and becomes a plain scroller under reduced motion. The visit map is MapLibre on OpenFreeMap tiles with real walking routes stored as coordinates, with an OpenStreetMap link as the fallback.

Plain pages

Each page is an ordinary HTML file that runs its own features on load, so a script added to one page works as normal and nothing needs a router. One shared script initialises only the features whose markup it finds, so any section or page can be deleted.

Plugins ScrollTrigger, Flip, Draggable, InertiaPlugin
Difficulty Intermediate
Smooth scroll Lenis integration
Includes HTML + JS + CSS source, documentation, AI setup prompt, lifetime updates

Lighthouse, as measured

Google Lighthouse on this template's demo (6 pages, lowest score shown), from the latest scan. A measurement of the demo as shipped, not a promise for your page.

Accessibility
100
Best practices
100

No performance score, on purpose. That figure depends on how you deploy: your server's compression and caching, your CDN, the connection and the device doing the test, none of which the code controls. The same page can score very differently on two consecutive runs, so measure it where it will live.

Questions about this template

It is a barber shop. What changes to make it a salon, tattoo studio or clinic?

Copy, portraits and five colour tokens. Each person is a colour token, a portrait shot on that colour and a few lines of HTML; the booking flow does not care whether it books a chair, a bed or a lesson. Rename the services and prices, replace the three portraits and the cut photos, set each person's token to their backdrop colour, and the pages, booking stage and ticket all follow.

Can customers really book through it?

Not on its own. The booking page is a complete front end: it collects a person, a service and a time, shows a total and issues a reference, but nothing is sent anywhere and no diary is checked. To take real bookings, point the confirm step at Fresha, Booksy, Calendly or a form handler such as Formspree, or link the Book buttons straight to your booking platform.

How do I add a fourth barber or stylist?

Add a colour token and its tone rule, then copy one entry in each place a person appears: the hero layer and tab, the triptych column, the booking card, the barbers wall and the footer block. Copy the profile page for their own page. Each time slot lists who it is taken for, so add their key to the slots that are busy for them.

The portraits need to match the colours. What if my photos do not?

The look depends on each portrait's backdrop matching its section, so shoot each person on seamless paper close to their colour, or pick the colour from the photo. The README shows how to sample the backdrop and set the token, and the image manifest regenerates every bundled file from your own originals at the right sizes.

How do the availability and service rules work?

They are data attributes you edit. Each time slot has a data-taken list of the people already booked at that time, and each service has a data-who list of the people who offer it. Change person and the flow strikes through anything not possible for them and releases a choice that no longer fits. It is a fixed demo diary, not a live calendar.

How do I change the booking days, times and opening hours?

The booking days are three fieldsets of time slots in book.html, one radio input per time with its day, time and taken list written on it, so a new day is a copied fieldset. Opening hours appear as plain lists on the home and visit pages, and one small table at the top of the script drives the today marker and the open-now line.

Paid template

Purchase to unlock the code.

Buying Appointment Booking Template opens the HTML, CSS and JavaScript source, the full documentation, an AI setup prompt for your editor, and every update we ship to it. Standard license: unlimited personal and commercial projects. Every paid product is tested for desktop and mobile layouts, reduced-motion handling, animation cleanup and keyboard controls wherever there is something to operate.

£29 Standard license, unlimited projects

Browse free effects

Or the whole library: the Vault, £79.20, one payment.

Documentation

Quick Start

Upload the folder to any static host and open index.html. Keep the six HTML files beside assets/ so relative links keep working. There is no build step, framework or package to install.

While editing, serve the folder with any local static server (for example python3 -m http.server) and open http://localhost:8000/index.html. Opening the files straight from disk works too.

GSAP, its plugins and Lenis load from a CDN, and the map (Visit page only) from unpkg and OpenFreeMap. Images, fonts, styles and the script are bundled locally.

Using It With Your Own Design

  1. Identity. Replace "Garnett & Sons", the three-bar SVG mark, the address, phone number and hours in the nav and footer of each page (they are repeated in every file so each page stands alone).
  2. People and colours. Each person is a key (lewis, nathan, shay), a colour token and a tone rule in assets/style.css. Rename the keys and set each token to the colour of that person's portrait backdrop (see Palette).
  3. Photographs. Replace the portraits and cut photos in assets/img/, keeping the names, or change the paths. The home hero takes any framed photo of each person at work; the portraits elsewhere (the three chairs, barbers wall, booking and profile) look best shot on seamless paper in each person's colour, so the photo meets its section without an edge. Rewrite captions and alt text from what your photographs show.
  4. Services and prices. Edit the price bands in prices.html, the service options in book.html and the headline-price strip under the three chairs on the home page. Prices are plain text; nothing is calculated except the booking total and the build-a-visit tool, which read the data-price and data-mins on each option.
  5. Booking. Connect the booking page to your own service before taking real bookings (see Booking).

Everything visual lives in assets/style.css; everything interactive lives in assets/script.js, organised as one function per feature that returns early when its markup is absent. Delete a section, or a whole page and its links, and the rest keeps working.

Pages and Configuration

File Content Interaction
index.html Hero, the three chairs with a headline-price strip, the shop, this week's cuts, then and now, a closing band (find us beside the three Book blocks) Backdrop pull ([data-hero]), shop mosaic ([data-shop]), cut wall filter ([data-wall]), then-and-now prints ([data-then])
book.html Three-step booking with ticket, then "before you come" Booking flow ([data-booking])
barbers.html Portrait wall, one block per person, who does what, hiring Portraits flick through each person's cuts on hover or focus ([data-flick])
lewis-garnett.html One person's profile: hero, signature cut, cut roll, list, week, quote Turn the head ([data-turn]), draggable cut roll ([data-roll-section])
prices.html Price bands per service group, build a visit, good to know Build a visit ([data-builder])
visit.html Shopfront, address, map with walking routes, hours, access Route map ([data-routes]), open-now line ([data-now])

A profile per person. Only one profile is built. Copy lewis-garnett.html for each person, change data-tone on <body> and on the sections that use their colour, and swap the photographs and copy. Then point that person's links (barbers wall, triptych, "other chairs" tiles) at the new file.

Tones. Any element with data-tone="cherry" (or green, lilac, ink, bone) takes that ground and the matching text colour; add the tone class to paint its background. <body data-tone> sets the nav colour for the first section.

Backdrop Pull

Each [data-layer] in the hero is one person: a <figure> with data-tone, data-name, data-chair, data-note and data-first, holding a framed photo in .hero__frame. The hero photos are ordinary framed photos of each person at work, so any staff shot works; nothing needs a matching backdrop. Each [data-tab] matches a layer by key. Dragging a tab down past a third of the travel unrolls that layer; less rolls it back. A tap, Enter or Space plays the full unroll. The caption and the hero's Book link update from the layer's attributes. To add a person, copy one layer and one tab.

Without JavaScript the first layer shows and the tabs are links to barbers.html#key.

Booking

The booking page is a front end only. It collects a person, a service and a time, shows the total and end time, and issues a reference on the last step, but nothing is sent anywhere and no diary is checked. To take real bookings:

  • link the "Book" buttons straight to your booking platform (Fresha, Booksy, Square Appointments, Calendly), or
  • submit the form to a handler such as Formspree, Netlify Forms or your own endpoint in confirmBooking() inside initBooking, and replace the demo reference with the one your service returns.

How the demo data works:

  • People are the barber radio group (value is the key, data-tone-key the colour, data-label and data-meta the ticket text).
  • Services are the service group with data-mins, data-price and data-who (the keys of people who offer it). Services a person does not offer are struck through when they are chosen.
  • Times are the slot group, one fieldset per day, with data-day, data-time and data-taken (keys of people already booked then). Taken times are struck through for the chosen person, and a chosen time that is no longer free releases itself.
  • Deep links: book.html?barber=nathan opens on step two in Nathan's colour; add &service=shave to tick the service. The home page, barbers page, profile and prices tool all link this way.

Without JavaScript all three lists and the phone number are visible, so the page still works as a "ring us" page.

Palette

Token Value Role Text on it
--cherry #BD0F25 Lewis, chair one; also buttons on bone bone, 5.48:1
--green #19573E Nathan, chair two (bottle green, the shop's tile band) bone, 7.22:1
--lilac #BEA1DC Shay, chair three ink, 8.31:1
--bone #F2ECE2 Light ground, tickets ink, 15.9:1
--ink #16110F Dark ground and text bone, 15.9:1

The three person colours were sampled from the portrait backdrops (the median of a clean corner across each person's photos). If you change a colour, sample your own backdrop in any image editor and set the token and its --*-rgb triple to that value, then check text contrast: each tone rule names its text colour and a dim alpha (--dim-a) measured for that ground. Light colours such as lilac take ink text; deep ones take bone.

Display type is Saira at its widest (125%) black italic, in capitals; body and labels are Golos Text 400 and 500. Both are self-hosted in assets/fonts/ (see Fonts under Images and Credits). To swap them, replace the @font-face rules at the top of assets/style.css and the two font preloads in each page's <head>, then set --font-display / --font-body.

Map and Routes

The Visit map is MapLibre GL on OpenFreeMap's Positron style (OpenStreetMap data, no API key, commercial use allowed). Set SHOP, STOPS and ROUTES in initRoutes to your own coordinates as [lng, lat]. Get real walking routes from a public OSRM router, for example https://routing.openstreetmap.de/routed-foot/route/v1/foot/<lng,lat>;<lng,lat>?overview=full&geometries=geojson, and keep the minutes and metres in the copy in step with the result. Keep the OpenStreetMap attribution. MapLibre's script and stylesheet are not in the page: loadMapLibre in assets/script.js adds them when the map comes within a screen of the viewport, so the page paints without them; change MAPLIBRE_JS and MAPLIBRE_CSS there to use another version or a self-hosted copy. Until the live map has drawn, and permanently without WebGL or the CDN, the map area shows assets/img/map-static.webp, a still of the same map with the route and pin, plus a link to the location on openstreetmap.org. After moving the pin, replace the still with a screenshot of your own live map (it carries the same OpenStreetMap and OpenMapTiles credit).

Opening hours live in the hours lists on the home and visit pages and in the OPEN table at the top of the script, which drives the "today" marker and the open-now line.

Accessibility and Fallbacks

  • Real links everywhere, a skip link, visible focus, one h1 per page and labelled controls.
  • The hero tabs are buttons with aria-pressed and work with Enter and Space; cut-wall chips are buttons with aria-pressed; the booking flow is native radio groups, moves focus to each step and announces it in a polite live region.
  • The turn-the-head viewer is a radio group as well as a drag; the cut roll has arrow buttons and responds to the arrow keys.
  • Reduced motion keeps every feature: the pull swaps instantly, the filter and steps change without movement, the cut roll becomes a native scroller and Lenis is not started.
  • Without JavaScript or with the GSAP CDN blocked, every page is readable: the first person shows in the hero, the booking page lists everything with the phone number and the profile shows all three head angles.

Dependencies

The demo is pinned to GSAP 3.15.0 with ScrollTrigger, Flip (home and book), Draggable and InertiaPlugin (profile), and Lenis 1.3.17 for optional smooth scrolling. Compatibility floor: GSAP 3.12+, with core and plugins on matching versions. The Visit page also loads MapLibre GL 4.7.1, on demand as the map nears the viewport. Smooth scrolling is off with ?smooth=off in the URL or data-smooth="off" on <html>.

Images and Credits

The download contains art-directed WebP derivatives in assets/img/. assets/img-manifest.json lists every file with its source, size and quality; replace a source (a local file in assets/img-src/ or a URL) and regenerate with the asset script, or simply drop in your own WebP files with the same names.

Responsive sizes. Every photograph wider than 900px also ships as -400 and -800 files, plus -1200 from masters of 1500px or more (manifest entries with variantOf). The pages serve them with srcset and a sizes value measured from each slot's rendered width (cover-cropped slots use the scaled image width), so phones download the small files, and the scripted swaps (the shop mosaic and the booking stage) carry the srcset across. If you replace a photo, replace its variants too, or delete the srcset attribute from that <img>. map-static-800.webp is the phone version of the map still. The first-screen photo on each page loads eagerly with fetchpriority="high"; everything below the fold is loading="lazy".

The portraits of the three barbers, Roy Garnett, all the finished cuts on coloured backdrops (cut-*, head-*), the shopfront (shopfront-v2), the shop photographs (shop-*, hero-shop-lewis) and shay-work are AI-generated images of people and places that do not exist, made for this template. Replace them with photographs of your real team and premises before launch; never present generated portraits as real staff or real clients.

map-static.webp is a screenshot of the live map: map data © OpenStreetMap contributors (ODbL), tiles © OpenMapTiles via OpenFreeMap.

The remaining photographs are licensed through Pexels, which permits use in website templates. They show unrelated people, not Garnett & Sons' staff or clients.

File Source Subject
fade-clippers.webp Pexels 39559262 Clippers on a fresh fade
trim-fade.webp Pexels 34702982 Trimmer on the neckline of a skin fade
hot-towel.webp Pexels 7447149 Hot towel, client reclined
kids-saturday.webp Pexels 7697364 Boy in the barber chair
scissors-comb.webp Pexels 7465903 Scissors and comb on a towel
pole-brick.webp Pexels 9280243 Barber's pole on red brick
fade-back.webp Pexels 12074386 Fresh fade, back view

Fonts

Both families are self-hosted in assets/fonts/ as the latin woff2 files Google Fonts serves, declared by the @font-face rules at the top of assets/style.css, so the pages make no font requests to another site: Saira (display, the 125% wide black italic) and Golos Text (body and labels; a variable font, one file for 400 and 500). Both are preloaded in each page's <head>.

Licence: SIL Open Font License 1.1, full text and copyright lines in assets/fonts/OFL.txt (Golos Text: Copyright 2019 The Golos Text Project Authors; Saira: Copyright 2020 The Saira Project Authors). Keep that file with the fonts. To use Google Fonts instead, delete the @font-face rules and the two font preloads and add the Google Fonts <link> to the <head>.

Worked examples, the events and programmatic API, and the class reference ship with the download, alongside the full source.