034
AI ready Refreshed

Travel & Tour Template

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

Includes the original v1 design as a separate download.

Multi-page tour operator website template on a committed bougainvillea magenta, with giant colour-on-colour headlines and a page for every trip where you drag along a measured climbing profile to move a rider along the real route on a live map. Worked example: a small-group cycling company in Girona with five trips.

ScrollTrigger advanced
10 more details
scrubdrag-interactionkeyboard-navigationcrossfadeclick-toggleparallaxscroll-revealstaggerform-validationprogressive-enhancement

Updated

About this template

A multi-page site for a tour operator that runs fixed departures in small groups: home, all trips, a full page for each trip, every date with the places left, the people, and an enquiry form. It is built on one committed colour, a deep bougainvillea magenta, with the headlines set huge in a pale blush on it, and a chalk-white field for the map, the dates and the form. The worked example is Can Riera Bike Holidays, a family cycling company in Girona, and its five trips, from four easy days on old railway paths to seven days between wine cellars.

Read the full template overview

Every trip page carries the signature. Under a real street map of the whole route sits the climbing profile of the ride, measured from elevation data and drawn as one big silhouette across a magenta band. Drag along it, or use the arrow keys, and a rider moves along the actual road on the map while the readout gives the day, the kilometre, the climbing so far and the nearest village, the photo for that stretch swaps in, and the village name rises above the profile in thin capitals. Six day buttons jump straight to each leg.

Around it the site works for the business: trip cards crossing giant region words, a finder that filters by month, length and level, a departures board grouped by month with ten seat dots per date and a waitlist state, a split of where the price goes, and an enquiry form that arrives prefilled with the trip and date the visitor chose and checks the places left as they add riders. Swap the trips, dates and photographs and it suits walking holidays, food and wine tours, e-bike hire or any small-group travel company.

Travel & Tour Template - website template preview

What's included

16 items
  • Complete multi-page site: home, trips, a page for each of the five trips drawn from one data file, dates and prices, about and guides, and an enquiry page, all plain page loads
  • Signature route scrubber on every trip: drag along a measured climbing profile and a rider marker moves along the real routed road on a live MapLibre map, with day, kilometre, climbing so far, height and nearest village read out
  • The village name rises over the profile in thin capitals as the rider reaches it, and the photograph for that day's stretch swaps in beside the map
  • Day buttons jump to each leg and fit the map to it; every day in the itinerary has a 'show on the map' link back to the scrubber
  • Real tiled maps on OpenFreeMap with no API key, loaded only when the map nears the screen, with an OpenStreetMap link in place before it loads or if WebGL is unavailable
  • Each trip's route geometry and heights baked into its own local JSON file, so the site calls no routing or elevation service
  • Home hero on colour alone: a giant blush headline on magenta, the next departure and places left as its first line, one tall photograph standing in the field
  • Trip cards cross giant region and headline words; the whole card is one link to its trip, on a native sideways rail with snap, buttons, keyboard and touch
  • Trip finder by month, length and level, with a live count and an empty state
  • Road bike or e-bike switch that reprices every date on the trip page
  • Where the price goes: an interactive split of the trip price into hotels, guide and van, food, bikes and fees
  • Enquiry form prefilled from the trip and date in the link, with a rider stepper, bike choice, a live estimate and a seat check that offers the waitlist
  • Phone navigation as its own magenta sheet: the six pages as stations on a line, Escape and outside-tap close, focus handled, current page marked, and a no-JS link to the footer page list
  • Enquire stays in the header at every width, so nothing floats over content on a phone
  • One self-hosted variable face, Chivo, and measured contrast recorded in the token block
  • Departures board grouped by month under giant month names: every row is one choosable radio that opens its places, prices and an 'Enquire for this departure' button, a filtered view per trip, and an empty state that says when the trip does run

Perfect for

5 use cases
  • Small-group cycling, walking and hiking holiday operators with fixed departures
  • Food and wine tours, retreats and workshops sold as dated trips
  • E-bike hire companies that also run guided rides
  • Rail journeys, island hopping and multi-centre trips sold as a sequence of stops
  • Local tour companies and travel agencies presenting a handful of signature itineraries

How it works

5 sections

Standalone pages, one page for every trip

Each page is an ordinary HTML file that runs its own features on load, so there is no router to learn and a page can be copied or deleted without breaking the others. The five trips share one trip page: a plain data file describes each trip, and the page draws the chosen one before it first paints, while the plain HTML holds a complete trip for visitors without scripts.

The route scrubber

Each trip page reads its own baked JSON file holding the routed legs, the stops and a height profile sampled along the line. The profile is a real slider control, so mouse, touch and the keyboard all drive it, and each position is turned into a point on the road, a height, the climbing so far and the nearest village. The map, readout, photograph and village name all follow that one value.

Maps that load late and fail politely

MapLibre GL and the OpenFreeMap style are fetched only when a map comes near the screen. Until then, and for good if WebGL or the network is unavailable, the map box holds a plain OpenStreetMap link. Gestures are cooperative, so the page scrolls normally over the map, and the attribution stays folded to its button.

Dates, seats and the enquiry

Every departure lives in the markup with its seat count, and the board, the trip pages and the enquiry form agree on it. Each row of the board is a single choosable control; choosing one opens its places, both prices and an enquiry link that carries the trip and date into the form, which then prefills itself and compares the riders against the places left.

Without JavaScript or motion

Every page is complete without scripts: the trips, the full itinerary with distances and climbing, every departure with its own enquiry link, and the price split as a table. Reduced motion removes the reveals, the line drawing and the rising names, and moves the rider without easing. If the GSAP CDN is blocked, the interface features still work.

Plugins ScrollTrigger
Difficulty Advanced
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

Which businesses does this tour template suit besides a cycling company?

Any operator that sells fixed departures in small groups: walking and hiking holidays, food and wine tours, retreats, e-bike hire with guided rides, rail or island-hopping journeys and local tour companies. The structure of trips, one trip in full, dates with places left and the people who lead them stays the same; you change the copy, the photographs, the route file and the departures list.

How do I put my own route on the map and the climbing profile?

Each trip's route, stops and heights are one JSON file in assets/data. The README shows how to request each leg from the public OpenStreetMap routers, sample heights along it and save the result, then update that trip's profile drawing and day figures in assets/trips.js. Distances in the copy should match the routed figures. A walking or ferry route works the same way with a different router.

How do I add a trip or a departure, or change the seats left?

Every trip is one entry in assets/trips.js, drawn by the shared trip page at trip.html?t=your-trip, plus its route file. Add its card to the trips page and home rail with region, days, level and months as data attributes for the finder. A departure is one row in the dates page and one entry in the enquiry data; change the seat dots and the number together.

Does the enquiry form send anything or take bookings?

No. It is a static front end: it collects the trip, date, riders, bike, name, email and a message, and shows a confirmation on the page, but nothing is sent or booked. Point the form at Formspree, Netlify Forms, your booking system or your CRM, and keep the estimate as a guide price rather than a quote.

Do the maps need an API key or an account?

No. The maps use MapLibre GL with OpenFreeMap tiles, which are OpenStreetMap data with no key, no account and commercial use allowed. Keep the OpenStreetMap attribution, which is a licence requirement. The site serves the route itself from a local file, so the only outside requests are the map library and tiles, loaded when a map nears the screen.

Can I change the magenta to my own brand colour?

Yes. The ground, its deep partner, the blush headline colour, chalk, ink and the small yellow signal are tokens at the top of the stylesheet, with the measured contrast for each pair. Pick a ground that keeps white body text above 4.5:1 and the headline tint above 3:1, because the headlines sit directly on the colour.

Paid template

Purchase to unlock the code.

Buying Travel & Tour 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

  1. Unzip the folder and serve it from any static host, or locally with a one-line server such as npx serve . or python3 -m http.server. There is no build step. Opened straight from the file system the pages work, but browsers block the route file from loading, so the maps and the scrubber only come alive when the folder is served. The trip pages still show each trip in full, with its static climbing profile.
  2. The pages are index.html, trips.html, trip.html (one page for all five trips: trip.html?t=emporda, coves, garrotxa, greenway, wine), dates.html, about.html and enquire.html. Each loads assets/style.css and assets/script.js and works on its own.
  3. Edit the copy, trips, prices and departures in the HTML, and the colour tokens at the top of assets/style.css.
  4. Replace the photographs in assets/img/ with your own at the same file names and proportions (see Images and Credits).
  5. Replace the trips in assets/trips.js and their routes in assets/data/<trip>-route.json with your own (see Trip pages and The route files).

Using It With Your Own Design

Every interactive part is found by a data- hook (data-menu, data-rail, data-teaser, data-ride, data-bike-switch, data-finder, data-board, data-split, data-enquiry) and its initialiser in assets/script.js returns at once when that hook is missing. Delete a section, or a whole page, and the rest keeps working. To lift one part into another site, copy its markup, its block of assets/style.css (each is headed by a comment) and its init function.

Navigation is plain links and ordinary page loads, so a click shows the next page at once. Every trip card and every row of the comparison table is one link to its trip page.

The header and footer are ordinary markup repeated on each page; when you add or rename a page, update the desktop links, the phone sheet (#site-menu) and the footer list on every page.

Pages and Configuration

Home (index.html)

  • Hero: the headline on the magenta ground, the next departure and places left as its first line, one tall photograph (home-hero) and a giant ghost word set by data-mark (decorative, hidden from screen readers).
  • Next departures: four stubs with ten seat dots each. A dot with class="is-free" is a free place; keep the aria-label on .seats in step.
  • Full-bleed photograph with a caption, home-object and its phone crop home-object-sm.
  • Route teaser (data-teaser): the stops list and a map that draws the route when it scrolls into view. Choosing a stop flies the map there and shows its photo card. The stop photos and lines are in the #stop-photos JSON block under the section.
  • Trip rail (data-rail): the trip cards cross the giant words "Five trips" and "from Girona", which drift sideways as the rail scrolls. It is a native scroll-snap row, so touch, trackpad and keyboard work; the arrow buttons appear only when the row overflows.
  • Guides and a guest quote.

Trips (trips.html)

  • Finder (data-finder): month, length and level buttons. Each card carries data-months (month numbers, 0 is January), data-days and data-level, which the finder reads. A region band (data-region-band) hides when none of its cards match, and an empty state offers to show all trips. Without JavaScript every trip is shown and the finder is hidden.
  • Region bands: a giant region word with its cards crossing it. To add a region, copy a band and change its word and note.
  • Comparison table: plain HTML.

Trip pages (trip.html?t=<trip>)

One page draws all five trips. assets/trips.js defines window.CanRieraTrips, one object per trip (name, region, days, level, road and e-bike prices, highlights, the day-by-day itinerary with its photos, departures, guide, FAQ and the drawn profile), followed by the renderer that turns a trip into the page. It is a plain script, loaded in the <head>: for ?t=coves it hides <main> for the moment it takes to draw the Costa Brava page, so the Empordà content never flashes first. trip.html itself holds the complete Empordà page as plain HTML, which is what shows without JavaScript and for an unknown ?t=.

  • Ride the route (data-ride, with data-route naming the trip's route file): the map, a button per day, the readout and the stretch photograph, then the profile band. The slider over the profile, the passed fill, the cursor and the rising village name are added when the route file loads.
  • Day by day: one row per day with distance and climbing from the route file. Each row's "Show day n on the map" button (with JavaScript) jumps the scrubber to that day.
  • Dates and prices with the road bike or e-bike switch (data-bike-switch).
  • Your guide: the button carries data-show-km (route kilometres) and jumps the scrubber there.

To add a trip, add an entry to CanRieraTrips with the same fields, bake its route file, and add its card, table row and departures to trips.html, index.html, dates.html and the #trip-data block in enquire.html. Distances and climbing in the copy should be the routed figures.

Dates and prices (dates.html)

  • Board (data-board): departures grouped by month under giant month names. Each row is one radio, with seat dots and a status chip (chip--open, chip--few for three places or fewer, chip--full for the waitlist). Choosing a row opens its summary underneath, with the places left, the road and e-bike prices and an "Enquire for this departure" button carrying ?trip= and &date=. This works with CSS alone, so it works without JavaScript too.
  • Month strip and trip select filter the board; dates.html?trip=wine opens it filtered to one trip, with a heading for that trip, a link to its page and a way back to every trip. The filter is applied while the page parses, so nothing moves after it paints. An empty month says which months the trip does run.

About and guides (about.html)

  • Where your price goes (data-split): the segments and their text are in the #split-data JSON block; the bar widths follow the amounts. Without JavaScript the same figures show as a table.
  • Getting there: a plain list. Check the journey times for your own location.

Enquire (enquire.html)

  • Form (data-enquiry): prefilled from ?trip= and &date=. The trips, prices and departures it uses are in the #trip-data JSON block at the bottom of the page; keep them in step with the dates page. The estimate multiplies riders by the price for the chosen bike (an own bike is the road price less €120) and warns when there are more riders than places left.
  • It sends nothing. Submitting checks the name and email and shows a confirmation on the page. Connect the form to Formspree, Netlify Forms, your booking system or CRM: set its action, or post the fields from the submit handler at the end of initEnquiry in assets/script.js.

The route files

Each trip has assets/data/<trip>-route.json, holding:

  • days: one entry per day with from, to, km (the routed distance used in the copy) and line, the routed road as [longitude, latitude] pairs.
  • stops: the villages, with their point on the line, the kilometre at which the rider reaches them, and night: true for the overnight stops shown with labels.
  • profile: [kilometre, height in metres, day] samples along the whole line.

The site never calls a routing or elevation service; it reads this file. To make your own:

  1. Route each leg with the public OpenStreetMap routers, for example https://routing.openstreetmap.de/routed-bike/route/v1/bike/<lng,lat>;<lng,lat>?overview=full&geometries=geojson (routed-foot for walking, routed-car for road or ferry legs). Send a User-Agent naming your site.
  2. Sample heights along the line, for example from the Open-Meteo elevation API (https://api.open-meteo.com/v1/elevation?latitude=...&longitude=..., up to 100 points per request).
  3. Save the result in the shape above. Then redraw the trip's profile.path in assets/trips.js from the same samples (x is kilometre over total distance times 1000, y is height scaled into the 220-unit-high view box), and update its day distances and climbing, the cards and the comparison table.

Palette

The tokens at the top of assets/style.css:

Token Value Use
--bougainvillea #B5156B The ground: home hero, page heads, the profile band, footer, phone menu; the route line; headings and links on chalk
--bougainvillea-deep #9E0F5C Pressed states, the footer foot, the passed part of the profile, ghost words
--blush #F7C6DD Headlines on magenta, large text only (4.29:1)
--white #FFFFFF Body text on magenta (6.39:1)
--chalk #F4F2EE The pale field
--ink / --ink-soft #26101B / #6B5560 Text on chalk (16.0:1 and 6.07:1)
--mimosa #FFE36E One small signal: few places left, the rider marker, the current page in the phone menu

Every translucent value uses the matching -rgb triple, so a new palette needs only these values. Keep white body text on your ground above 4.5:1 and the headline tint above 3:1.

Accessibility and Fallbacks

  • The phone menu is a real button with aria-expanded and aria-controls; Escape and a tap outside close it, focus moves to the first link and back to the button, and the current page is marked with aria-current. Without JavaScript a "Pages" link in its place jumps to the footer list of every page.
  • Enquire stays in the header bar at every width and never floats over content.
  • The route scrubber is a native range control with a spoken value ("Day 2, kilometre 41.3, 380 metres climbed, near Banyoles"); arrow keys, Page Up and Down, Home and End all work. The day buttons report their pressed state.
  • Seat availability is dots plus words, never colour alone.
  • Maps are labelled regions, their markers are hidden from assistive technology, and gestures are cooperative so the page scrolls over them. Until a map loads, or if WebGL is unavailable, the box holds an OpenStreetMap link.
  • With reduced motion there are no reveals, line drawing, rising names or eased jumps. Without JavaScript every page is complete.

Dependencies

  • GSAP 3.15.0 with ScrollTrigger (works with 3.12+), for reveals, the route drawing in, the rising village names and crossfades. If the CDN is blocked, the interface features still work and the content shows without motion.
  • MapLibre GL 4.7.1 with OpenFreeMap tiles (no API key; keep the OpenStreetMap attribution) on the home and trip pages, loaded only when a map nears the viewport. The URLs are MAP_JS, MAP_CSS and MAP_STYLE near the top of assets/script.js.
  • Route data from the OSRM bike router on routing.openstreetmap.de (© OpenStreetMap contributors, ODbL) and heights from the Open-Meteo elevation API (Copernicus DEM GLO-90), baked into the route file at build time.

Fonts

One variable family, Chivo, self-hosted as the Latin subset in assets/fonts/chivo-latin.woff2 and declared at the top of assets/style.css (weights 200 to 900). Every page preloads it. Licence: SIL Open Font License 1.1, full text in assets/fonts/OFL.txt (Copyright 2019 The Chivo Project Authors, https://github.com/Omnibus-Type/Chivo).

Images and Credits

Photographs are bundled as graded, resized WebP derivatives in assets/img/. assets/img-manifest.json lists each output with its source, crop and grade; re-bake with bun scripts/build-template-assets.ts travel-tour-template --force from the GSAP Vault repository, or replace a file in assets/img/ with your own at the same name and proportions. home-hero-sm, trip-emporda-sm, home-object-sm and cadaques-aerial-sm and every other -sm file are the phone crops of their larger files, and the trip cards have -400 and -760 copies for their srcset.

Generated images. AI-generated (Codex image engine, October 2026) images of a fictional company and people; the masters are in assets/img-src/ (gen-*.jpg): home-hero (baked as home-hero and home-hero-sm), trip-emporda (baked as trip-emporda, trip-emporda-wide and trip-emporda-sm), home-object, day-lunch, guide-marta, guide-jordi, guide-nuria, team-workshop. They depict no real person, business or brand.

Stock photographs, from Pexels under the Pexels licence.

File Source
trip-coves https://www.pexels.com/photo/cyclists-riding-on-scenic-coastal-road-36909460/
trip-garrotxa https://www.pexels.com/photo/scenic-tree-lined-road-in-kastamonu-turkiye-38277790/
trip-greenway, stop-banyoles https://www.pexels.com/photo/pavement-among-trees-by-the-lake-23893302/
trip-wine https://www.pexels.com/photo/lush-vineyard-in-catalonia-s-scenic-landscape-39426740/
stop-girona https://www.pexels.com/photo/colorful-riverside-buildings-in-girona-spain-30166261/
getting-there https://www.pexels.com/photo/onyar-river-in-girona-13759651/
stop-besalu https://www.pexels.com/photo/medieval-stone-bridge-in-besalu-spain-33212788/
stop-besalu-river https://www.pexels.com/photo/old-stone-viaduct-on-river-14737198/
stop-peratallada https://www.pexels.com/photo/view-of-a-medieval-village-pals-in-catalonia-spain-22756496/
stop-begur https://www.pexels.com/photo/scenic-view-of-cala-sa-boadella-bay-in-summer-33389206/
stop-lescala https://www.pexels.com/photo/boats-on-the-shore-and-white-residential-buildings-in-calella-spain-10412987/
stop-roses https://www.pexels.com/photo/scenic-coastal-view-in-roses-catalunya-32784602/
stop-cadaques https://www.pexels.com/photo/boats-in-marina-of-cadaques-spain-20843248/
cadaques-aerial, cadaques-aerial-sm https://www.pexels.com/photo/sailboats-in-harbor-by-the-town-in-spain-9500327/
group-stop https://www.pexels.com/photo/group-of-friends-on-a-bike-adventure-in-charming-alley-33952724/
month-spring https://www.pexels.com/photo/clouds-over-poppies-blooming-in-a-vast-field-25440345/
month-autumn https://www.pexels.com/photo/sunlit-orchard-in-countryside-16883480/
enquire-dusk https://www.pexels.com/photo/seaside-town-at-sunset-5497372/
stop-santfeliu, santfeliu-wide, santfeliu-wide-sm https://www.pexels.com/photo/brown-rock-formation-on-sea-under-blue-sky-10080995/
stop-tossa, hero-coves, hero-coves-sm https://www.pexels.com/photo/aerial-view-of-tossa-de-mar-catalunya-spain-29111220/
coves-bay, coves-bay-sm https://www.pexels.com/photo/scenic-view-of-boats-in-tossa-de-mar-spain-33443467/
stop-castellfollit, hero-garrotxa, hero-garrotxa-sm https://www.pexels.com/photo/town-on-rocks-12008676/
garrotxa-river, garrotxa-river-sm https://www.pexels.com/photo/sunlit-forest-and-footbridge-around-river-12008672/
greenway-path https://www.pexels.com/photo/a-man-in-a-jacket-riding-a-bicycle-11962728/
vall-bas https://www.pexels.com/photo/narrow-alley-in-between-houses-12917592/
hero-greenway, hero-greenway-sm https://www.pexels.com/photo/pavement-among-trees-by-the-lake-23893302/
stop-figueres https://www.pexels.com/photo/church-tower-in-figueres-17866955/
stop-peralada https://www.pexels.com/photo/castillo-de-peralada-espana-28216223/
vineyard-albera, hero-wine, hero-wine-sm https://www.pexels.com/photo/scenic-vineyard-landscape-under-dramatic-sky-34559687/
stop-llanca, llanca-wide, llanca-wide-sm https://www.pexels.com/photo/white-red-and-black-sail-boat-on-gray-sand-88566/

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