How to setup OwnerRez vacation rental widgets in Gatsby.js (or any other React project)
March 24th 2020
Background
OwnerReservations.com (OwnerRez) is a popular vacation rental management platform that handles bookings and payments for property managers and syncs with other booking platforms like Airbnb and HomeAway. OwnerRez offers a handful of HTML widgets that you can embed into your website to enable guests to view vacancies for the rental on a calendar and request to book by submitting a form.
Breaking down the problem
In my Gatsby.js project visiteggharbor.com, I attempted to embed the various OwnerRez widgets using the provided embed codes and had issues with the widget loading.
First in your OwnerRez account, navigate to Settings > Widgets > Create Widget to generate the embed code for your widget. It will looks something like this:
<!-- testwidget -->
<!-- OwnerRez Multiple Month Calendar widget for Point Beach House -->
<div class="ownerrez-widget" data-propertyId="cdfd55b69b49464199cb424075a49f4b" data-widget-type="testwidget - Multiple Month Calendar" data-widgetId="f68fb359a8de404a83caf96e0a236d55"></div>
<script src="https://secure.ownerreservations.com/widget.js"></script>
When you code/paste this embed code into your React code (removing the comments) and open up the console in your browser, the widget will not be rendered and you will get a handful of errors.
const Reserve = () => {
return(
<>
<div class="ownerrez-widget" data-propertyId="cdfd55b69b49464199cb424075a49f4b" data-widget-type="testwidget - Multiple Month Calendar" data-widgetId="f68fb359a8de404a83caf96e0a236d55"></div>
<script src="https://secure.ownerreservations.com/widget.js"></script>
</>
)
}
Warning: Invalid DOM property `class`. Did you mean `className`?
Warning: React does not recognize the `data-propertyId` prop on a DOM element.
Warning: React does not recognize the `data-widgetId` prop on a DOM element.
We can go ahead and fix these errors by renaming the props as shown below, however the script will be targeting the wrong props and again, no widget will be rendered in the browser.
const Reserve = () => {
return(
<>
<div className="ownerrez-widget" data-property-id="cdfd55b69b49464199cb424075a49f4b" data-widget-type="testwidget - Multiple Month Calendar" data-widget-id="f68fb359a8de404a83caf96e0a236d55"></div>
<script src="https://secure.ownerreservations.com/widget.js"></script>
</>
)
}
Let's try modifying the widget.js script that we are loading. Navigate to the src link and copy the widget.js script into a new file in your project. Edit line 362 with the new element properties below:
loadWidget(el, el.getAttribute("data-widget-id"), el.getAttribute("data-property-id"), tracker);
Then load the widget.js script into the react component where your widgets will reside:
import '../components/widget.js'
const Reserve = () => {
return(
<>
<div className="ownerrez-widget" data-property-id="cdfd55b69b49464199cb424075a49f4b" data-widget-type="testwidget - Multiple Month Calendar" data-widget-id="f68fb359a8de404a83caf96e0a236d55"></div>
<script src="https://secure.ownerreservations.com/widget.js"></script>
</>
)
}
Now when you view your site in the browser, the widget should be rendered, however if you reload the site or try to restart the dev server, the widget will not be rendered. You can test this by commenting out the script import and reloading the page.
I couldn't quite figure out why the script would only render the widget one time, but I believe that it may have to do with how the react code is being compiled. Upon inspection of the calendar widget in the browser, notice how it is being rendered as an <iframe> with the widget-id and property-id being used as query parameters in the src URL.
As a workaround to avoid using the widget.js script entirely, we can use an <iframe> in our React code and provide to it the proper src URL and other properties.
The Solution
To embed the calendar widget in our React code, we will use an iframe element with a src URL containing the values from the data-widget-id and data-property-id properties found in the original widget embed code.
import '../components/widget.js'
const Reserve = () => {
const DATA_WIDGET_ID = 'YOUR_DATA_WIDGET_ID'
const DATA_PROPERTY_ID = 'YOUR_DATA_PROPERTY_ID'
return(
<>
<iframe src={`https://secure.ownerreservations.com/widgets/${DATA_WIDGET_ID}?seq=0&propertyKey=${DATA_PROPERTY_ID}`} frameborder="0" scrolling="no" seamless="seamless" allowtransparency="true" ></iframe>
</>
)
}
Now when you view your site in the browser, the widget should be rendered on every page refresh as you would expect.
You can style the <iframe> with the CSS techniques you would typically use in React:
- Using inline styles
- Using classes (by passing a string as the className prop to the iframe) and importing the CSS stylesheet
- Using CSS-in-JS with one of many CSS-in-JS libraries. Below is an example of styling the widget using styled-components.
import React from 'react'
import styled from 'styled-components'
import '../components/widget.js'
const Widget = styled(iframe)`
display: block;
margin: 0 auto;
width: 100%;
max-width: 300px;
height: 321px;
border: 0;
padding: 20px;
`
const Reserve = () => {
const DATA_WIDGET_ID = 'YOUR_DATA_WIDGET_ID'
const DATA_PROPERTY_ID = 'YOUR_DATA_PROPERTY_ID'
return(
<>
<Widget src={`https://secure.ownerreservations.com/widgets/${DATA_WIDGET_ID}?seq=0&propertyKey=${DATA_PROPERTY_ID}`} frameborder="0" scrolling="no" seamless="seamless" allowtransparency="true" ></Widget>
</>
)
}