Travel Page React template for Tailwind CSS v4
v1.0.0Added in 1.14.0
A React travel agency and tour operator template: tour search, tour cards, a day by day detail sheet, destinations and a custom trip form.
The search card in the hero filters the tours live as you type a country, region or tour name, pick a travel window in the date range picker (a bottom sheet on phones) or step the travelers up and down: a tour stays when it has a departure in that window with enough seats, and the count is announced. Search glides down to the tours. On phones the search is a stacked card, the tours become a swipeable snap rail and a Find a tour bar slides up once the hero scrolls away, taking you back to the search. Every tour card opens its detail sheet (from the right on desktop, a bottom sheet with a grab handle on phones): the rating, duration, group and pace, the day by day itinerary, what is and is not included, and the dates as radio cards with seats left (sold out and too small departures are disabled, arrow keys move between them). Changing travelers updates the total and the deposit live; Reserve your spot spins, then confirms the held seats. The heart on a card saves the tour with a burst. Region chips filter the destination tiles; a tile with tours searches that destination, a tile without tours jumps to the custom trip form with the destination filled in. The FAQ opens one answer at a time. The custom trip form checks name and email, focuses the first problem, takes budget and interest chips, spins on submit and then thanks you.
Travel 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 travel-page, together with Marketing Section, Marketing Header, Marketing Footer, FAQ Section, Feature Grid and 18 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.
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 travel-pageTravel 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 TravelPage from @/components/templates/travel-page.
// app/page.tsx
"use client"
import Link from "next/link"
import { TravelPage, type TravelReservation } from "@/components/templates/travel-page"
async function reserve({ tour, departure, travelers }: TravelReservation) {
await fetch("/api/holds", {
method: "POST",
body: JSON.stringify({ tour: tour.id, departure: departure.id, travelers }),
})
}
export default function HomeRoute() {
return <TravelPage linkComponent={Link} onReserve={reserve} />
}Props
toursdefault"TRAVEL_TOURS"TravelTour[]{ id, title, destination, region, route, days, groupSize, rating, reviews, price, previousPrice?, scene, color, image?, badge?, pace?, summary, itinerary: { day, title, description? }[], included, excluded?, departures: { id, start (yyyy-mm-dd), seats, price? }[], href?, favorite? }. scene picks the drawn cover (mountains, coast, desert, city, savanna, fjord, ruins) tinted with color; image replaces it. price is the per person from price; href is carried along for your own links (the card opens the detail sheet).
destinationsdefault"TRAVEL_DESTINATIONS"TravelDestination[]{ name, region, note?, scene, color, image? } tiles. The tour count and from price come from the tours whose destination matches the name; a destination without tours links to the custom trip form. An empty array hides the section.
reviewsdefault"TRAVEL_REVIEWS"Testimonial[]Traveler quotes for the reviews grid (the TestimonialsSection shape, with rating).
faqsdefault"TRAVEL_FAQS"FaqItem[]{ question, answer } pairs for the FAQ; an empty array hides it.
statsdefault"TRAVEL_STATS"StatsSectionItem[]{ value, decimals?, prefix?, suffix?, label, description? } numbers for the stats section; an empty array hides it.
gallerydefault"TRAVEL_GALLERY"TravelGalleryItem[]{ id, caption, location, scene, color, image? } tiles of the gallery band; the first one is large from 768px.
whydefault"TRAVEL_WHY"FeatureGridItem[]The Why travel with us cards: { icon, title, description } for the FeatureGrid.
phonedefault"(303) 555-0142"stringThe office number in the header, the phone menu and the custom trip band (a tel: link); empty hides it.
depositdefault300numberThe deposit per traveler: the last hero point and the line under the total in the detail sheet; 0 hides both.
datePresetsdefault"TRAVEL_DATE_PRESETS"DateRangePreset[]{ label, value: { from, to } | () => range, key? } quick ranges beside the search calendar (chips above it on phones); an empty array hides them.
labelsPartial<TravelPageLabels>Every string on the page: the brand, the hero, the search, the section headings, the detail sheet, the form and its errors. The ones that take a count, a price or a name are functions (call, matches, dayCount, seatsLeft, tourCount, totalFor, deposit, reservedDescription, successDescription and more).
currencydefault"USD"stringISO currency of every price, total, deposit and budget chip.
localedefault""stringIntl locale for prices, dates and numbers; empty uses the UIProvider's, else en-US.
onSearch(search: TravelSearch) => voidRuns on Search and on a destination tile with { destination, dates: { from, to }, travelers }. The tours filter live either way; use it to fetch or to sync the URL.
onReserve(reservation: TravelReservation) => void | Promise<unknown>Runs on Reserve your spot with { tour, departure, travelers, total }. A returned promise keeps the button loading; a rejection shows labels.reserveFailed in the sheet. Without it the page pretends for 900 ms, then confirms.
onInquiry(values: TravelInquiryValues) => void | Promise<unknown>Runs on Send my trip ideas with { name, email, destination, season, travelers, budget, interests, notes }. A returned promise keeps the button loading; a rejection keeps the form and shows labels.failed. Without it the page pretends for 900 ms, then thanks.
onFavoriteChange(tour: TravelTour, favorite: boolean) => void | Promise<unknown>Runs when a heart is pressed. A returned promise keeps the heart on while pending; a rejection rolls it back.
featuredCountdefault6numberTour cards shown from 768px before Show all; phones get every match in the rail.
tonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"Accents: the stars, the chosen departure, the itinerary dots, the region, budget and interest chips, the date range selection and the stat numbers.
ctaTonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"Search, Plan a trip, Reserve your spot, Send my trip ideas and the Find a tour bar.
favoriteTonedefault"neutral""neutral" | "brand" | "success" | "warning" | "danger" | "info"The heart on a saved tour; neutral is white on the cover.
radiusdefault"lg""none" | "sm" | "md" | "lg"Corners of the tour, destination, gallery and form cards: 0 / 12 / 16 / 24px; the covers inside follow.
backgrounddefault"soft""plain" | "soft" | "glow" | "aurora" | "grid" | "dots"The main background: plain is the bare page color; the others tint the page and add a wash, a glow, an aurora, a grid or dots over the first screen.
backgroundColordefault"oklch(0.66 0.12 60)"stringThe tint of the main background, a warm sand by default.
bandBackgrounddefault"muted""muted" | "tinted" | "gradient" | "dots"The secondary background of every second section (destinations, stats, reviews and the custom trip form with all sections on). Cards and fields inside are lifted one step above it.
bandColordefault"oklch(0.66 0.12 60)"stringThe tint of tinted and gradient bands; left equal to backgroundColor it follows it.
showDestinationsdefaulttruebooleanThe destination tiles with the region chips (and their header link).
showWhydefaulttruebooleanThe Why travel with us cards.
showStatsdefaulttruebooleanThe stats section.
showGallerydefaulttruebooleanThe gallery band of drawn travel moments.
showReviewsdefaulttruebooleanThe reviews grid.
showFaqdefaulttruebooleanThe FAQ with its contact card.
showInquirydefaulttruebooleanThe Plan a custom trip band and form. Off, Plan a trip in the header calls the office and destinations without tours search instead.
stickySearchBardefaulttruebooleanThe Find a tour bar pinned to the bottom of phones once the hero scrolls away.
headerdefaulttruebooleanThe sticky header with the brand, the section links, the phone number and Plan a trip.
footerdefaulttruebooleanThe footer with Tours, Travel and Company links and the seller of travel line.
headerPropsPartial<MarketingHeaderProps>Anything for MarketingHeader (layout, variant, items...); wins over the page's own values.
footerPropsPartial<MarketingFooterProps>Anything for MarketingFooter (variant, columns, socials, newsletter...).
whyPropsPartial<FeatureGridProps>Anything for the Why travel with us FeatureGrid (layout, columns, card...).
statsPropsPartial<StatsSectionProps>Anything for the StatsSection (variant, size, countUp...).
reviewsPropsPartial<TestimonialsSectionProps>Anything for the reviews TestimonialsSection (layout, columns, card...).
faqPropsPartial<FaqSectionProps>Anything for the FaqSection (layout, searchable, categories...).
stickyBarPropsPartial<StickyCtaBarProps>Anything for the Find a tour StickyCtaBar (variant, size, showOn...).
animateIndefaulttruebooleanThe hero and the search rise in once when the page mounts on the client; never during hydration, under reduced motion or in thumbnails.
linkComponent(props: LinkComponentProps) => ReactNodeThe router link for the header, footer, feature and FAQ links (next/link in an app).
classNamestringClasses for the root.
classNamesPartial<Record<TravelPageSlot, string>>Classes for header, hero, search, tours, tour, cover, detail, destinations, destination, why, stats, gallery, reviews, faq, inquiry, form, stickyBar and footer.
Parts
TRAVEL_PAGE_SAMPLE
constantAll the sample content in one object: tours, destinations, reviews, faqs, stats and gallery.
TRAVEL_TOURS
constantTen Wayfare Journeys tours on four continents, from Utah's Mighty Five to a Serengeti safari, with itineraries and 2027 departures.
TRAVEL_DESTINATIONS
constantTwelve destinations in Europe, Asia, Africa and the Americas; Portugal and Nepal are custom trips only.
TRAVEL_REVIEWS
constantSix five star traveler quotes, each naming the tour and the month.
TRAVEL_FAQS
constantSeven booking questions: group size, inclusions, deposit, changes, solo travel, fitness and custom trips.
TRAVEL_STATS
constantFour numbers: years running, travelers, average rating and repeat travelers.
TRAVEL_GALLERY
constantSix drawn moments from recent departures with captions and places.
TRAVEL_WHY
constantSix reasons to travel with Wayfare, with lucide icons.
TRAVEL_DATE_PRESETS
constantSpring, summer and fall 2027 and winter 2027 to 2028 as search ranges.
TRAVEL_BUDGETS
constantThe four budget chips of the custom trip form as per person [min, max] ranges.
DEFAULT_TRAVEL_PAGE_LABELS
constantThe English strings.
TravelPageProps
typeProps of TravelPage, including the attributes of the root element.
TravelPageLabels
typeEvery string of the page.
TravelPageRadius
type"none" | "sm" | "md" | "lg".
TravelPageSlot
typeThe keys of classNames.
TravelTour
typeOne tour: facts, price, drawn cover, itinerary, inclusions and departures.
TravelItineraryDay
type{ day, title, description? }: one stop of the day by day itinerary.
TravelDeparture
type{ id, start, seats, price? }: one date of a tour.
TravelDestination
typeOne destination tile.
TravelGalleryItem
typeOne gallery tile.
TravelRegion
type"europe" | "asia" | "africa" | "americas".
TravelScene
type"mountains" | "coast" | "desert" | "city" | "savanna" | "fjord" | "ruins": the drawn covers.
TravelSearch
typeWhat onSearch receives: { destination, dates, travelers }.
TravelReservation
typeWhat onReserve receives: { tour, departure, travelers, total }.
TravelInquiryValues
typeWhat onInquiry receives.
TravelBudget
type"under-3k" | "3k-6k" | "6k-10k" | "10k-plus".
TravelInterest
type"hiking" | "food" | "culture" | "wildlife" | "beaches" | "photography" | "slow".
TravelSeason
type"flexible" | "spring" | "summer" | "fall" | "winter".
Examples
Brand accents
tone, ctaTone and a red favoriteTone on a glow page with tinted bands: orange stars, chips and buttons, red hearts.
A tour catalog, search first
Tours, destinations and FAQ only, nine featured tours on square-ish cards and a teal aurora: a lean booking site for one operator.
European prices
currency="EUR" and locale="de-DE": euro prices, German date and number formats, English copy.
When booking fails
onReserve and onInquiry reject: after the spinner the sheet and the form keep everything and show the error.
Inside a site layout
No header, footer or sticky bar, on a plain page with dotted bands: the sections alone.
Dependencies
Files
- components/templates/travel-page.tsx
- components/templates/travel-page-data.ts
FAQ
Is the React Travel Page template free?
The preview, props and docs are free; copying the source needs a Pro plan. See plans.
How do I install Travel Page?
Run npx wingo-ui@latest add travel-page. It also adds the Wingo UI items it builds on (Marketing Section, Marketing Header, Marketing Footer, FAQ Section, Feature Grid and 18 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/travel-page.
How does Travel Page behave on phones?
The search card in the hero filters the tours live as you type a country, region or tour name, pick a travel window in the date range picker (a bottom sheet on phones) or step the travelers up and down: a tour stays when it has a departure in that window with enough seats, and the count is announced.