Introduction
The Vaylo Widget is a powerful, embeddable booking solution that allows you to integrate tour booking functionality directly into your website. Built with React and TypeScript, it provides a seamless user experience with support for multiple languages, customizable themes, and comprehensive payment integration.
Key Features
- 🌍 Multi-language support (English, Norwegian, Swedish)
- 🎨 Fully customizable themes and styling
- 💳 Integrated payment processing
- 📱 Responsive design for all devices
- 🔒 Secure booking flow
- ♿ Accessibility-focused UI components
Choose your widget
The same script powers more than one widget. Pick the one that matches the page you are building:
-
type: "default"— search form, tour list, and the complete booking flow. Use it on your search page and on your booking page. -
type: "trip_details"— a compact "book this trip" box listing the upcoming departures of one tour. Use it on a single tour page. This is the most common integration, and it has its own guide with a copy-paste example, a tour-tag lookup, and a troubleshooting table.
Installation
Follow these three simple steps to integrate the Vaylo booking widget into your website:
Step 1: Embed the Widget Script
Add the widget script inside your
<head> tag. Select the appropriate
environment URL:
<script src="https://widget.bookingsystem.se/res_widget_script.iife.js"></script>
<script src="https://stage.widget.bookingsystem.se/res_widget_script.iife.js"></script>
<script src="https://dev.widget.bookingsystem.se/res_widget_script.iife.js"></script>
Step 2: Create a Container Element
Add a <div> element in your page
where you want the widget to appear. You can use any ID
you prefer:
<div id="vaylo-widget"></div>
Step 3: Initialize the Widget
Add the initialization script, typically at the bottom
of your
<body> tag or in your JavaScript
file:
window.addEventListener("load", function () {
Widget.mount({
containerID: "vaylo-widget",
});
});
type parameter
will default to "default" if not provided.
Requirements
For Default Mode (tour list with search):
- A valid container element ID
For Trip Details Mode (type: "trip_details"):
- A valid container element ID
-
type: "trip_details"— without it you get the search widget instead -
tourTagis required: the ID of the tour tag whose departures are listed. Without it the widget shows an empty state. See Finding your Tour Tag ID. -
redirects.bookingURLis required (unless it is already set on your Vaylo account): the absolute URL of the page where the Book button sends the visitor. That page must mount the"default"widget. -
departureFrom(optional, defaults to today) anddurationin months (optional, defaults to3) control which departures are listed
Quick Start
Complete Integration Example
Here's a complete example showing all three steps together:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Booking Site</title>
<!-- Step 1: Embed the Widget Script -->
<script src="https://widget.bookingsystem.se/res_widget_script.iife.js"></script>
</head>
<body>
<!-- Step 2: Create Container Element -->
<div id="vaylo-widget"></div>
<!-- Step 3: Initialize the Widget -->
<script>
window.addEventListener("load", function () {
Widget.mount({
containerID: "vaylo-widget",
});
});
</script>
</body>
</html>
Widget Types
There is only one script to load. The
type option decides which widget that
script renders inside your container. You can use
different types on different pages of the same website.
| type | What the visitor sees | Typical page | Must be provided |
|---|---|---|---|
"default"
default value
|
Search form, tour list, and the full booking flow (traveller details, payment, confirmation) | Search / "All tours" page and the booking page | containerID |
"trip_details" |
A compact list of the upcoming departures for one tour tag, with price, availability, and a Book button | A single tour / campaign landing page (usually in the sidebar) |
containerID,
tourTag,
redirects.bookingURL
|
"payment" |
Only the payment screen for a booking that already exists | A "pay for your booking" page opened from a Vaylo payment link |
containerID plus the
booking parameters that Vaylo adds to
the link
|
"trip_details".
If you want visitors to search across all of your tours,
you want "default".
Trip Details Widget (type: "trip_details")
The Trip Details widget turns any page on your website into a bookable tour page. You write the tour description, photos, and itinerary yourself — the widget adds the part that has to stay in sync with your booking system: the upcoming departure dates, live prices, remaining seats, and a Book button.
<div>, and call
Widget.mount() with three things:
containerID,
tourTag (which tour to show), and
redirects.bookingURL (where the
Book button should send the visitor).
Nothing else is required — language, currency,
colours, and fonts are already taken from your Vaylo
account settings.
What the widget renders
Inside your container, from top to bottom, the widget renders:
- Your phone number and e-mail address as click-to-call and click-to-mail links. These come from your Vaylo account settings, not from the mount configuration.
- One card per departure, sorted by departure date (soonest first). Each card shows the departure and return date, the tour name, the price per person, how many seats are left, and a Book button.
- A "no suggestions available" message when no departure matches your settings. See Troubleshooting if you see this unexpectedly.
searchKeys,
itemPerPage,
showAllToursByDefault) have no effect here.
How the two pages fit together
The Trip Details widget is deliberately small: it lists departures and hands the visitor over to your booking page. That means a working setup uses two pages:
PAGE 1 - Your tour page PAGE 2 - Your booking page
https://yoursite.com/tours/lofoten https://yoursite.com/booking
+------------------------------+ +------------------------------+
| Your own content: | | |
| photos, itinerary, text | | Widget.mount({ |
| | click | containerID: "...", |
| +------------------------+ | "Book" | type: "default" |
| | trip_details widget | | --------> | }) |
| | 15 Jun - 22 Jun | | | |
| | Lofoten Islands | | | Traveller details -> |
| | 12 500 SEK per person | | | Payment -> Confirmation |
| | 4 spots left [Book] | | | |
| +------------------------+ | +------------------------------+
+------------------------------+
type: "trip_details" type: "default"
tourTag: 4 (reads the tour from the URL)
redirects.bookingURL: page 2
When the visitor clicks Book, the
widget sends them to
redirects.bookingURL and appends the
selected departure to the URL:
https://yoursite.com/booking?widget_screen=booking&tour=237
The "default" widget on your booking page
reads those two parameters and opens the booking flow
for that exact departure. You do not have to build
anything to read the URL yourself.
redirects.bookingURL at the existing page.
Re-use the same booking page for every tour page —
one booking page is enough for your whole website.
Installation in 4 steps
Step 1: Load the script (once per page)
Add this inside <head>. It is the
same script for every widget type — see
Installation for the staging
and development URLs.
<script src="https://widget.bookingsystem.se/res_widget_script.iife.js"></script>
Step 2: Add an empty container
Put this where you want the booking box to appear
— typically in the sidebar next to your tour
description. Any ID works, as long as it matches
containerID in step 3.
<div id="trip-details-widget"></div>
Step 3: Mount the Trip Details widget
Add this near the end of your
<body>. This is the smallest
configuration that works:
<script>
window.addEventListener("load", function () {
Widget.mount({
containerID: "trip-details-widget",
type: "trip_details",
tourTag: 4,
redirects: {
bookingURL: "https://yoursite.com/booking"
}
});
});
</script>
Step 4: Make sure your booking page has the default widget
On the page you used as
bookingURL, mount the
"default" widget. This is the page that
collects traveller details and takes the payment.
<div id="booking-widget"></div>
<script>
window.addEventListener("load", function () {
Widget.mount({
containerID: "booking-widget",
type: "default",
redirects: {
successURL: "https://yoursite.com/thank-you"
}
});
});
</script>
Complete copy-paste example
A full tour page with your own content and the Trip
Details widget in a sidebar. Replace
tourTag and the URLs with your own values.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lofoten Islands - Book your trip</title>
<!-- Step 1: Load the widget script -->
<script src="https://widget.bookingsystem.se/res_widget_script.iife.js"></script>
<style>
.tour-page {
display: grid;
grid-template-columns: 1fr 360px;
gap: 2rem;
max-width: 1200px;
margin: 0 auto;
}
/* Keep the booking box visible while the visitor scrolls */
#trip-details-widget {
position: sticky;
top: 2rem;
border: 1px solid #e5e7eb;
border-radius: 12px;
overflow: hidden;
}
@media (max-width: 900px) {
.tour-page { grid-template-columns: 1fr; }
#trip-details-widget { position: static; }
}
</style>
</head>
<body>
<div class="tour-page">
<article>
<h1>Lofoten Islands</h1>
<p>Your own tour description, photos and itinerary go here.</p>
</article>
<!-- Step 2: The widget container -->
<aside>
<div id="trip-details-widget"></div>
</aside>
</div>
<!-- Step 3: Mount the widget -->
<script>
window.addEventListener("load", function () {
Widget.mount({
containerID: "trip-details-widget",
type: "trip_details",
// Which tour to show (required)
tourTag: 4,
// Which departures to show (optional)
departureFrom: "2026-01-01",
duration: 12,
// Where the Book button goes (required, must be absolute)
redirects: {
bookingURL: "https://yoursite.com/booking",
successURL: "https://yoursite.com/thank-you"
},
// Presentation (optional - falls back to your account settings)
locale: "en",
currencyCode: "SEK",
dateFormat: "dd MMM, yyyy"
});
});
</script>
</body>
</html>
Configuration reference for this widget type
Every option below is optional except the three marked Required. Any option you leave out falls back to your Vaylo account settings, and then to the widget default.
| Option | Type | Default | What it does here |
|---|---|---|---|
containerID
Required
|
string | — |
ID of the empty
<div> the widget is
rendered into. Must exist in the page
before mount() is called.
|
type
Required
|
string | "default" |
Must be
"trip_details" for this
widget. If you leave it out you get the
search widget instead.
|
tourTag
Required
|
number | — | The tour tag ID whose departures are listed. Without it the widget renders the empty state and loads nothing. See Finding your Tour Tag ID. |
redirects.bookingURL |
string | Your account's booking redirect URL |
Absolute URL of the page that hosts the
"default" widget. The
Book button sends the
visitor here. Required unless it is
already configured on your Vaylo
account.
|
redirects.successURL |
string | Your account's success redirect URL | Absolute URL the visitor lands on after a completed booking. Used by the booking page, not by this widget — set it there. |
departureFrom |
string | today |
Earliest departure date to list, in
YYYY-MM-DD format.
|
duration |
number | 3 |
How many months after
departureFrom to keep
listing departures.
|
currencyCode |
string | Your account's default currency |
ISO code the prices are shown in, for
example "SEK",
"NOK",
"EUR".
|
locale |
string | Your account's default language |
Language of the widget's own labels
("per person", "spots left", "Book"):
"en", "sv", or
"nb".
|
dateFormat |
string | Your account's default date format |
How the departure and return dates are
written, for example
"dd MMM, yyyy".
|
allowWaitlistBooking |
boolean | Your account's waitlist setting |
When true, fully booked
departures show
Join waitlist instead
of a disabled button.
|
theme |
object | Your account's theme | Colours, fonts, and font sizes. See Theme Customization. |
classPrefix |
string | "rm_widget" |
Prefix for the widget's CSS class names, if you need to avoid clashing with your own styles. See Styling. |
redirects.bookingURL must be an
absolute URL including
https:// — a relative path such as
"/booking" will not work.
departureFrom must be exactly
YYYY-MM-DD and
duration must be a number
(12, not "12"); anything else
can stop the widget from rendering.
Finding your Tour Tag ID
tourTag is a number, not the tag's name. It
is the single value you need per tour page, so it is
worth writing them all down once. There are three ways
to get it:
Option 1: From your Vaylo admin panel (recommended)
Open the tour tags list in your Vaylo admin panel. Each
tag has an ID — that number is your
tourTag value. If you cannot find it, ask
your Vaylo contact for "the tour tag IDs for our tours";
it is a one-line answer.
Option 2: Read it from a search page URL
If you already run the "default" widget
somewhere with the Tour tag filter
enabled:
- Open that page.
- Pick your tour in the Tour tag filter and run the search.
-
Look at the address bar. You will see
tour_tag=4— the number is the ID you need.
https://yoursite.com/search?widget_screen=list&tour_tag=4
^
this is your tourTag
Option 3: One tag per tour page
The usual setup is one tour tag per tour, so each tour
page mounts the widget with its own
tourTag. Keep a small table like this and
the integration stays trivial to maintain:
| Your page | tourTag |
|---|---|
/tours/lofoten |
4 |
/tours/iceland |
7 |
/tours/greenland |
11 |
Widget.mount() call. Then editors
can publish new tour pages without touching any code.
Which departures are shown
The widget always lists departures inside a date window that it calculates for you:
window start = departureFrom (default: today)
window end = departureFrom + duration months (default: 3 months)
Departures outside that window are not listed, even if they are on sale in Vaylo. Departures are always sorted with the soonest first.
| Goal | Configuration | Result |
|---|---|---|
| Always show the next 12 months (recommended) | duration: 12 |
Rolling window from today. Nothing to maintain. |
| Show one specific season |
departureFrom: "2026-06-01",
duration: 3
|
Only departures between 1 Jun 2026 and 1 Sep 2026. |
| Show everything you have on sale | duration: 36 |
A three-year window — in practice every published departure. |
departureFrom to a hard-coded date, that
date will eventually be in the past and the list will
look wrong. Unless you are showing one specific season,
leave departureFrom out and only set
duration — the window then follows
today's date automatically.
Sold-out departures and the waitlist
Each card shows the remaining capacity that Vaylo reports for that departure:
- Seats available — the card shows "N spots left" and an active Book button.
- Fully booked, waitlist off — the card shows "Fully booked" and the Book button is disabled. The departure stays visible, so visitors can see that the trip is popular.
- Fully booked, waitlist on — the button becomes Join waitlist and continues into the normal booking flow, which is registered as a waitlist booking.
The waitlist is normally switched on for your whole
account in Vaylo. Set
allowWaitlistBooking: true in
Widget.mount() only if you want to enable
it for this page alone.
Styling the widget
Colours, fonts, and font sizes come from your Vaylo
theme, and you can override them per page with the
theme option. Two
things are left to your own CSS: where
the widget sits, and how wide it is.
The widget fills the width of its container, so size the container, not the widget. This is a typical sidebar placement:
#trip-details-widget {
width: 100%;
max-width: 360px;
position: sticky; /* follows the visitor while scrolling */
top: 2rem;
border: 1px solid #e5e7eb;
border-radius: 12px;
overflow: hidden;
}
@media (max-width: 900px) {
#trip-details-widget {
max-width: 100%;
position: static;
}
}
CSS class hooks
Every element the widget renders carries a stable class
name, so you can style individual parts without fighting
the theme. The names below use the default prefix
rm_widget; change it with the
classPrefix option
(classPrefix: "acme" gives
acme_tour_name, and so on).
| Class | Element |
|---|---|
.widget-main-container |
Outermost wrapper around the whole widget |
.rm_widget_tour_suggestion_container
|
The departure list as a whole |
.rm_widget_telephone |
Click-to-call phone row |
.rm_widget_email |
Click-to-mail e-mail row |
.rm_widget_tour_suggestion_list_item
|
One departure card |
.rm_widget_dates |
Departure – return date line |
.rm_widget_tour_name |
Tour name |
.rm_widget_availability |
"N spots left" / "Fully booked" pill |
.rm_widget_tour_suggestion_book_button
|
Book / Join waitlist button |
theme option over CSS overrides for colours
and fonts. Theme values are applied consistently across
every screen of the booking flow, so the booking page
keeps matching your tour page.
Several tour pages on one website
Each tour page mounts the widget once with its own
tourTag and points at the same shared
booking page. Nothing else changes between pages:
// On /tours/lofoten
Widget.mount({
containerID: "trip-details-widget",
type: "trip_details",
tourTag: 4,
duration: 12,
redirects: { bookingURL: "https://yoursite.com/booking" }
});
// On /tours/iceland
Widget.mount({
containerID: "trip-details-widget",
type: "trip_details",
tourTag: 7,
duration: 12,
redirects: { bookingURL: "https://yoursite.com/booking" }
});
Widget.mount() once per page load. If you
need two booking boxes on the same page (for example one
at the top and one at the bottom), talk to your Vaylo
contact first — use a single container and CSS
placement instead.
Single-page apps (React, Vue, Next.js, ...)
Mount the widget after the container
element exists in the DOM, and only once per page. In
React that means calling
Widget.mount() from
useEffect after the script has loaded:
import { useEffect } from "react";
const SCRIPT_SRC = "https://widget.bookingsystem.se/res_widget_script.iife.js";
export const TripDetailsWidget = ({ tourTag }) => {
useEffect(() => {
const mountWidget = () =>
window.Widget?.mount({
containerID: "trip-details-widget",
type: "trip_details",
tourTag,
duration: 12,
redirects: { bookingURL: "https://yoursite.com/booking" },
});
// The script may already be there from an earlier page load
if (window.Widget) {
mountWidget();
return;
}
const script = document.createElement("script");
script.src = SCRIPT_SRC;
script.async = true;
script.addEventListener("load", mountWidget);
document.head.appendChild(script);
return () => script.removeEventListener("load", mountWidget);
}, [tourTag]);
return <div id="trip-details-widget" />;
};
<a href> rather than a
client-side router push) so the widget starts from a
clean state.
bookingURL. That is
intentional — it works the same whether your
booking page is part of the same app or a completely
separate page.
Troubleshooting
| What you see | Most likely cause | Fix |
|---|---|---|
| Nothing at all appears |
The container ID does not match, or
mount() ran before the
element existed
|
Check that
containerID matches the
<div id="...">
exactly, and call
mount() from
window.addEventListener("load", ...).
The browser console will log
[Widget] Mount target "..." not
found
if the element is missing.
|
| The search form and tour list appear instead of the departure list |
type is missing or
misspelled
|
Set
type: "trip_details"
— exactly that string, in
lowercase with an underscore.
|
| "There are no suggestions available at the moment." |
tourTag is missing or wrong
|
Confirm the ID as described in
Finding your Tour Tag ID. Pass it as a number
(tourTag: 4).
|
| Same empty message, but the tag is correct | No departure falls inside the date window |
Increase duration (try
duration: 12) and remove any
hard-coded
departureFrom in the past.
See
Which departures are shown.
|
| Fewer departures than expected | The missing departures are outside the window, or not published in Vaylo |
Widen duration, then check
that the departures are published and
carry the same tour tag.
|
| The Book button does nothing |
redirects.bookingURL is
empty, or is a relative path
|
Set it to an absolute URL including
https://, for example
"https://yoursite.com/booking".
|
| The Book button lands on a page with no booking flow |
The target page has no
"default" widget
|
Mount the
"default" widget on that
page — see step 4 of
Installation in 4 steps.
|
| The Book button is greyed out | The departure is fully booked and the waitlist is off |
Expected behaviour. Enable the waitlist
in Vaylo, or set
allowWaitlistBooking: true,
to offer
Join waitlist instead.
|
| Prices are in the wrong currency |
currencyCode is not set for
this page
|
Add the ISO code, for example
currencyCode: "NOK". Without
it the account default is used.
|
| Labels are in the wrong language |
locale is not set for this
page
|
Add
locale: "sv",
"nb", or
"en". On a multi-language
site, pass the language of the current
page.
|
| Phone number or e-mail address is wrong or missing | Those come from your Vaylo account settings |
Update the contact details in Vaylo. They
cannot be set from
Widget.mount().
|
| The widget is too wide or too narrow | The widget fills its container | Size the container with your own CSS — see Styling the widget. |
Go-live checklist
-
Script tag points at the
production URL
(
widget.bookingsystem.se), not staging or development. -
type: "trip_details"andtourTagare set on every tour page, with the right tag per page. -
redirects.bookingURLis an absolutehttps://URL, and that page mounts the"default"widget. -
redirects.successURLis set on the booking page and points at your own thank-you page. -
durationis wide enough to cover the departures you sell, and no staledepartureFromis left behind. -
localeandcurrencyCodematch the page the widget is on. - You completed one real test booking end to end, and checked the widget on a phone-sized screen.
Configuration Options
The widget accepts a configuration object with the following properties. You can easily customize the widget's appearance and behavior:
| Property | Type | Description |
|---|---|---|
containerID |
string | ID of the DOM element where the widget will be mounted |
type |
string | Which widget to render: "default" (tour list with search and the booking flow), "trip_details" (departure list for one tour — see the Trip Details Widget guide), or "payment". Defaults to "default". |
theme |
object | Full control over colors, fonts, font sizes, and header height |
locale |
string | Language of the widget (e.g., "en", "sv", "nb") |
currencyCode |
string | ISO currency code (e.g., "SEK", "USD", "EUR") |
itemPerPage |
number |
Number of tours to display per page.
Only used by
type: "default" — the
trip details widget is not paginated.
|
dateFormat |
string | Customize how dates appear (e.g., "dd MMM, yyyy") |
departureFrom |
string |
Earliest departure date to list (Format:
"YYYY-MM-DD"). Defaults to today. Used
by
type: "trip_details" only.
|
duration |
number |
Number of months to look ahead from
departureFrom. Defaults to
3. Used by
type: "trip_details" only.
|
tourTag |
number |
The tour tag ID whose departures are
listed.
Required for
type: "trip_details" and
ignored by the other types. See
Finding your Tour Tag ID.
|
allowWaitlistBooking |
boolean | Allow visitors to join a waitlist on fully booked departures. Defaults to your Vaylo account setting. |
showAllToursByDefault |
boolean |
Show the tour list before the visitor
searches. Only used by
type: "default".
|
classPrefix |
string |
Prefix for the widget's CSS class names.
Defaults to
"rm_widget". See
CSS class hooks.
|
searchKeys |
array | Define which search filters are available to users. See Search Behavior section for all available options. |
redirects |
object | Define where users are sent on search, booking, and after booking success. See Redirect URLs section for details. |
Example Configuration
Widget.mount({
containerID: "vaylo-widget",
type: "default",
locale: "en",
currencyCode: "SEK",
itemPerPage: 10,
dateFormat: "dd MMM, yyyy",
departureFrom: "2025-04-24",
duration: 3,
tourTag: 101,
showAllToursByDefault: false,
searchKeys: [
"tour_tag",
"tags",
"country",
"location",
"category",
"passenger_types",
"from_departure_date",
"to_departure_date",
],
redirects: {
searchURL: "https://yourdomain.com/search",
bookingURL: "https://yourdomain.com/bookings",
successURL: "https://yourdomain.com/success",
},
theme: {
color: {
themeColor: "#FF5733",
textColor: "#0A2540",
secondaryTextColor: "#999999",
backgroundColor: "#ffffff",
foregroundColor: "#E9EBEE",
borderColor: "#D1D9E6",
},
font: {
default: "Inter",
heading: "Playfair Display",
},
size: {
heading: 31,
title: 20,
regular: 16,
default: 13,
},
headerHeight: 81,
},
});
What You Can Change Yourself
You can freely adjust the following configuration options to customize the widget behavior and appearance:
Colors and Fonts
Customize inside the theme section:
- Theme colors (themeColor, textColor, backgroundColor, etc.)
- Font families (default and heading fonts)
- Font sizes (heading, title, regular, default)
- Header height
Text Language
Set the locale property to change the
widget language:
"en"- English"sv"- Swedish"nb"- Norwegian Bokmål
Displayed Tours
Control which tours are shown by adjusting:
-
tourTag- The tour tag ID whose departures are listed (type: "trip_details"only, and required there) -
departureFrom- Earliest departure date (Format: YYYY-MM-DD, defaults to today;type: "trip_details"only) -
duration- Number of months to look ahead (defaults to 3;type: "trip_details"only) -
showAllToursByDefault- Whether to display all tours before the user searches (type: "default"only)
type: "default", the shown date range comes
from the visitor's own search, not from
departureFrom /
duration.
Search Behavior
Configure available search filters using the
searchKeys array.
Important: Keys must match exactly
(case-sensitive).
Available search keys:
"tour_tag""tags""category""country""location""destination""passenger_types""number_of_passengers""from_departure_date""to_departure_date""pickup_locations""departure_date"
Redirect URLs
Define user flow by setting URLs in the
redirects section:
-
searchURL- Where users are redirected on search -
bookingURL- Where users go when booking -
successURL- Post-booking success page
Widget Container CSS
Customize the container element's appearance with your own CSS:
#vaylo-widget {
width: 1200px;
max-width: 100%;
margin: -10rem auto 0;
}
You can adjust width, margins, padding, and other CSS properties to fit your page layout.
Theme Customization
Customize the widget's appearance by providing a theme configuration with colors, fonts, sizes, and header height:
Color Properties
| Property | Type | Description |
|---|---|---|
themeColor |
string | Primary brand color for buttons, links, and accents |
textColor |
string | Main text color |
secondaryTextColor |
string | Secondary text color for less prominent text |
backgroundColor |
string | Background color of the widget |
foregroundColor |
string | Foreground/surface color for cards and panels |
borderColor |
string | Border color for inputs and dividers |
Font Properties
| Property | Type | Description |
|---|---|---|
default |
string | Default font family for body text |
heading |
string | Font family for headings and titles |
Available font options: "Inter", "Poppins", "Montserrat", "Playfair Display", "Raleway", "Bebas Neue", "Roboto", "Open Sans", "Lato", "Doto", "Quicksand"
Size Properties
| Property | Type | Description |
|---|---|---|
heading |
number | Font size for main headings (in pixels) |
title |
number | Font size for section titles (in pixels) |
regular |
number | Font size for regular text (in pixels) |
default |
number | Base font size (in pixels) |
Other Properties
| Property | Type | Description |
|---|---|---|
headerHeight |
number | Gap spacing from your website's header (in pixels). Used for sticky positioning to prevent overlap with your site's header |
Complete Theme Example
Widget.mount({
containerID: "vaylo-widget",
locale: "en",
currencyCode: "SEK",
theme: {
color: {
themeColor: "#2563eb",
textColor: "#0A2540",
secondaryTextColor: "#64748b",
backgroundColor: "#ffffff",
foregroundColor: "#f8fafc",
borderColor: "#e2e8f0",
},
font: {
default: "Inter",
heading: "Poppins",
},
size: {
heading: 28,
title: 20,
regular: 16,
default: 14,
},
headerHeight: 70,
},
redirects: {
searchURL: "https://yourdomain.com/search"
}
});
Usage Examples
Basic HTML Integration
Simple integration in a static HTML page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Booking Site</title>
<!-- Load Widget Script -->
<script src="https://widget.bookingsystem.se/res_widget_script.iife.js"></script>
<style>
#vaylo-widget {
width: 1200px;
max-width: 100%;
margin: 0 auto;
}
</style>
</head>
<body>
<div id="vaylo-widget"></div>
<script>
window.addEventListener("load", function () {
Widget.mount({
containerID: "vaylo-widget",
type: "default",
locale: "en",
currencyCode: "SEK",
itemPerPage: 10,
dateFormat: "dd MMM, yyyy",
redirects: {
searchURL: "https://yourdomain.com/search",
bookingURL: "https://yourdomain.com/bookings",
successURL: "https://yourdomain.com/success"
}
});
});
</script>
</body>
</html>
React Integration
Using the widget in a React application:
import { useEffect } from 'react';
function BookingWidget() {
useEffect(() => {
const script = document.createElement('script');
script.src = 'https://widget.bookingsystem.se/res_widget_script.iife.js';
script.async = true;
script.onload = () => {
if (window.Widget) {
window.Widget.mount({
containerID: "vaylo-widget",
type: "default",
locale: "en",
currencyCode: "SEK",
itemPerPage: 10,
dateFormat: "dd MMM, yyyy",
redirects: {
searchURL: "https://yourdomain.com/search",
bookingURL: "https://yourdomain.com/bookings",
successURL: "https://yourdomain.com/success"
}
});
}
};
document.head.appendChild(script);
return () => {
// Cleanup if needed
document.head.removeChild(script);
};
}, []);
return (
<div
id="vaylo-widget"
style={{ width: '1200px', maxWidth: '100%', margin: '0 auto' }}
/>
);
}
export default BookingWidget;
Vue.js Integration
Using the widget in a Vue.js application:
<template>
<div id="vaylo-widget" style="width: 1200px; max-width: 100%; margin: 0 auto;"></div>
</template>
<script>
export default {
name: 'BookingWidget',
mounted() {
const script = document.createElement('script');
script.src = 'https://widget.bookingsystem.se/res_widget_script.iife.js';
script.async = true;
script.onload = () => {
if (window.Widget) {
window.Widget.mount({
containerID: "vaylo-widget",
type: "default",
locale: this.$i18n?.locale || "en",
currencyCode: "SEK",
itemPerPage: 10,
dateFormat: "dd MMM, yyyy",
redirects: {
searchURL: "https://yourdomain.com/search",
bookingURL: "https://yourdomain.com/bookings",
successURL: "https://yourdomain.com/success"
}
});
}
};
document.head.appendChild(script);
},
beforeUnmount() {
// Cleanup if needed
}
};
</script>
With Custom Theme
Applying custom colors and fonts:
<script>
window.addEventListener("load", function () {
Widget.mount({
containerID: "vaylo-widget",
type: "default",
locale: "en",
currencyCode: "SEK",
itemPerPage: 10,
dateFormat: "dd MMM, yyyy",
theme: {
color: {
themeColor: "#8b5cf6",
textColor: "#1e1b4b",
secondaryTextColor: "#64748b",
backgroundColor: "#ffffff",
foregroundColor: "#faf5ff",
borderColor: "#e9d5ff"
},
font: {
default: "Poppins",
heading: "Playfair Display"
},
size: {
heading: 32,
title: 22,
regular: 16,
default: 14
},
headerHeight: 80
},
redirects: {
searchURL: "https://yourdomain.com/search",
bookingURL: "https://yourdomain.com/bookings",
successURL: "https://yourdomain.com/success"
}
});
});
</script>
Advanced Usage
Custom Search Filters
Control which search filters are available to users:
Widget.mount({
containerID: "vaylo-widget",
locale: "en",
currencyCode: "SEK",
itemPerPage: 10,
dateFormat: "dd MMM, yyyy",
// Only enable specific search filters
searchKeys: [
"country",
"category",
"from_departure_date",
"to_departure_date"
],
redirects: {
searchURL: "https://yourdomain.com/search",
bookingURL: "https://yourdomain.com/bookings",
successURL: "https://yourdomain.com/success"
}
});
Multiple Widgets on One Page
Display different widget configurations on the same page:
<!-- First Widget: Summer Tours -->
<div id="summer-tours-widget"></div>
<!-- Second Widget: Winter Tours -->
<div id="winter-tours-widget"></div>
<script>
window.addEventListener("load", function () {
// Summer tours widget
Widget.mount({
containerID: "summer-tours-widget",
locale: "en",
currencyCode: "SEK",
itemPerPage: 6,
dateFormat: "dd MMM, yyyy",
redirects: {
searchURL: "https://yourdomain.com/search?type=summer"
}
});
// Winter tours widget
Widget.mount({
containerID: "winter-tours-widget",
locale: "en",
currencyCode: "SEK",
itemPerPage: 6,
dateFormat: "dd MMM, yyyy",
redirects: {
searchURL: "https://yourdomain.com/search?type=winter"
}
});
});
</script>
Date Range Configuration
Control the date range for available tours using the
departureFrom and
duration parameters. These settings
determine which tour dates are displayed to users.
type: "trip_details".
departureFrom and
duration are read by the
Trip Details Widget only.
With type: "default" the date range comes
from the visitor's search instead, so setting these two
options there has no effect.
How It Works
The date range is calculated as follows:
-
Start Date: Specified by
departureFrom(format: YYYY-MM-DD) -
End Date: Automatically calculated
as
departureFrom+durationmonths -
Default Behavior: If not specified,
departureFromis today anddurationis3— so the widget shows the next three months. It never shows "all future dates" by default; widendurationif you sell departures further ahead.
Parameter Details
| Parameter | Type | Description |
|---|---|---|
departureFrom |
string | Starting date for tour availability in YYYY-MM-DD format (e.g., "2025-04-01") |
duration |
number | Number of months from the start date to display tours (e.g., 12 for one year) |
Example 1: Fixed Date Range (12 Months)
Display tours from April 1, 2025, through March 31, 2026:
Widget.mount({
containerID: "vaylo-widget",
type: "trip_details",
tourTag: 4,
locale: "en",
currencyCode: "SEK",
itemPerPage: 10,
dateFormat: "dd MMM, yyyy",
departureFrom: "2025-04-01",
duration: 12,
redirects: {
searchURL: "https://yourdomain.com/search",
bookingURL: "https://yourdomain.com/bookings",
successURL: "https://yourdomain.com/success"
}
});
Example 2: Dynamic Date Range
Set the start date dynamically to today's date:
const today = new Date().toISOString().split('T')[0]; // Format: YYYY-MM-DD
Widget.mount({
containerID: "vaylo-widget",
type: "trip_details",
tourTag: 4,
locale: "en",
currencyCode: "SEK",
departureFrom: today,
duration: 12,
redirects: {
searchURL: "https://yourdomain.com/search",
bookingURL: "https://yourdomain.com/bookings",
successURL: "https://yourdomain.com/success"
}
});
Best Practices
- Plan Ahead: Set a date range that aligns with your tour planning and booking cycles
- Consider Lead Time: Account for how far in advance customers typically book tours
- Regular Updates: If using fixed dates, remember to update them periodically
- Test Coverage: Ensure your date range covers all tours you want to display