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
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 Suggestions Mode (type: "trip_details"):
- A valid container element ID
-
tourTagis required to filter and display specific tours -
departureFromdate is important for showing available tours within the specified timeframe -
duration(in months) to define the date range for tour availability
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>
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 | Widget display mode: "default" (tour list with search) or "trip_details" (tour suggestions view) |
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 |
dateFormat |
string | Customize how dates appear (e.g., "dd MMM, yyyy") |
departureFrom |
string | Earliest departure date to show tours (Format: "YYYY-MM-DD") |
duration |
number | Number of months to look ahead for tours from departureFrom date |
tourTag |
number | Filter tours by a specific tour tag ID (optional) |
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:
-
departureFrom- Earliest departure date (Format: YYYY-MM-DD) -
duration- Number of months to look ahead -
tourTag- Filter tours by a specific tour tag ID -
showAllToursByDefault- Whether to display all tours before user searches
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"
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.
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, the widget shows all available future dates
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",
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",
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