Dynamically Rendering Widgets

tip

This walkthrough is for web-based widget solutions. For more general setup information regarding a web-based widget, please go to Connecting the Widget to your Website.

Overview#

There are cases where you might want different widgets to appear within the same web experience, depending on user selection. Rather than load multiple widgets on the same page, or redirect to different pages, you can display based on Dynamic Rendering.

For state-based rendering languages like React, this functionality may be already built-in. Here's a live example using the tabs from this documentation:

<Tabs
defaultValue="widget1"
lazy="true"
values={[
{label: 'Calendar View', value: 'widget1'},
{label: 'List View', value: 'widget2'},
]}
>
<TabItem value="widget1">
<iframe src="https://widget.arrive.com/index.html?ui-components=map,event-calendar,checkout&destination-venue-id=8" id="renderedWidget" height="600px" width="100%" scrolling="yes"/>
</TabItem>
<TabItem value="widget2">
<iframe src="https://widget.arrive.com/index.html?ui-components=map,event-list,checkout&destination-venue-id=8" id="renderedWidget" height="600px" width="100%" scrolling="yes"/>
</TabItem>
</Tabs>

This walkthrough provides an overview of how to create the same experience as above in the simplest way possible, agnostic to what framework you're using. The end result will be an HTML page that includes two tabbed widgets, switching between an event calendar and an event list.


Required Steps#

To start, you should have multiple widgets that you'd like to render on the page. You can learn more about customizing your widget in the Integration Guides.

The widgets should be provided to you as a URL. For the sake of this walkthrough, they'll be called widget1 and widget2.

You'll also need access to the code for the webpage that you'd like to add the widgets to and some basic JavaScript/HTML knowledge. If your site is running on another framework - no worries; although you won't be able to use the code examples, the functionality still applies.

Adding HTML#

Our widgets are rendered via an <iframe> html element on your site. The iframe code you'll add to your HTML will look something like this:

<iframe src="URL" id="ID" height="600px" width="100%" scrolling="yes" />

With URL being the URL option you'd like to show when the user enters the page (either widget1 or widget2), and ID being a unique reference ID for the iframe that you'll use in the function call.

Adding JavaScript#

We'll need a function that renders the different widgets inside your iframe. Fortunately, we can access the URL of the iframe via the src attribute.

function renderWidget(id, url) {
document.getElementById(id).src = url;
}

In this function, we're providing the id of the iframe as well as the url that we'd like to change it to. The function can either be added to and referenced from its own .js file or be included in a <script> tag in the HTML.

Adding Interaction#

Now that we have the widget as well as the function to render it, we'll need a way for the user initiate the action. You can use any type of interactive element as long as it can trigger an event (such as radio buttons, dropdowns, even inputs or clickable sections) - in this example, we'll be using buttons.

<button onclick="renderWidget('ID', 'widget1')">Render Widget 1</button>
<button onclick="renderWidget('ID', 'widget2')">Render Widget 2</button>

With ID being the ID of the iframe.

That's it! If you click a button, you'll re-render the widget with the selected URL.

Additional Options#

Now that you've built the core dynamically rendering widgets, you can add in optional customization.

Customization#

The example has some basic classes for you to build off if you'd like, as well as highlighted sections that show what is and is not editable on the page.

Since the interactive inputs are built directly in the HTML, you have full control of how the elements look and feel. Although this example uses a tabbed approach, feel free to stylize the components to render in any manner you'd like. We'd recommend adding at least a clear header and descriptor explaining the core functionality of the widget (to find and book parking), but how you do so is up to you.

tip

Anything inside the <iframe> component cannot be manipulated or stylized. Anything surrounding the widget is completely customizable.

Disabling the Active Input#

To reduce the number of loads required for the iframe component, it's recommended to disable the input for the "active tab", or currently-rendered widget. This can be handled a variety of ways depending on your framework; in this case, the example is in plain JavaScript.

To toggle the tabs:

function toggleTabs(element, tabContainerId) {
// Get all of the tabs within the tab container, specified by the tabContainerId
const tabs = document.getElementById(tabContainerId).childNodes;
// Enable every tab except for the one that was clicked
tabs.forEach(tab => {
tab.disabled = (tab == element);
});
}

Once you have tab toggle, your onclick event will need to call a wrapping function that toggles the tabs and renders the widget:

function tabSelected(element, tabContainerId, widgetId, url) {
renderWidget(widgetId, url);
toggleTabs(element, tabContainerId);
}

And the interactive element will need to call itself and the container id in the call:

<div id="tabContainer">
<button onclick="tabSelected(this, 'tabContainer', 'ID', 'widget1')">Render Widget 1</button>
<button onclick="tabSelected(this, 'tabContainer', 'ID', 'widget2')">Render Widget 2</button>
</div>

Alternatively, you can create an Event Listener to look for onclick events rather than passing in the element into the call.

Storing the widget URL#

If you're using a CMS tool, it's highly recommended to include the widget urls as an input option so that you can swap out the the tabs on the fly. Although it's rare for a widget to change once added, this provides more flexibility should you like to add or change the UI components, venues, parking locations, etc.

Final Result#

The resulting HTML code is shown below. Please feel free to copy and make use as your own.

<html>
<!--
Use this code as an example and playground for how to dynamically render widgets.
Feel free to copy it, add, edit, or remove components - this is for your reference.
-->
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style>
/*
Highlighted sections used for description:
These should be removed if you're using this code in your site.
*/
.key {
background-color: rgba(229, 229, 229, 0.5);
padding: 5px;
width: fit-content;
}
.iframe--container {
border: 2px dashed red;
padding: 5px;
}
.controls--container {
border: 2px solid blue;
padding: 5px;
}
/*
Example Styling
*/
body {
background-color: #fff;
color: #5c5962;
font-family: -apple-system, BlinkMacSystemFont, "helvetica neue", helvetica, roboto, noto, "segoe ui", arial, sans-serif;
font-size: inherit;
line-height: 1.4;
}
.heading {
color: #27262b;
font-size: 36px;
font-weight: 300;
}
.btn {
appearance: none;
background-color: #f7f7f7;
border-radius: 3px;
border-width: 0;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12), 0 3px 10px rgba(0, 0, 0, 0.08);
box-sizing: border-box;
color: #2869e6;
cursor: pointer;
display: inline-block;
font-family: inherit;
font-size: inherit;
font-weight: 500;
line-height: 1.5;
margin: 0;
padding-bottom: 0.3em;
padding-left: 1em;
padding-right: 1em;
padding-top: 0.3em;
text-decoration: none;
vertical-align: baseline;
}
.btn:disabled, .btn:disabled:hover {
background-color: rgba(229, 229, 229, 0.5);
background-image: none;
box-shadow: none;
color: rgba(102, 102, 102, 0.5);
cursor: default;
}
.btn-green {
background-color: #10ac7d;
background-image: linear-gradient(#13cc95, #10ac7d);
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25), 0 4px 10px rgba(0, 0, 0, 0.12);
color: #fff;
}
.btn-green:hover {
background-color: #0fa276;
background-image: linear-gradient(#12be8b, #0fa276);
color: #fff;
}
</style>
<!-- Example Script. This includes the tab toggling feature, which is optional. -->
<script type="text/javascript">
// The dynamic render function - all you need.
function renderWidget(id, url) {
document.getElementById(id).src = url;
}
///////////////////// Add-on functions /////////////////////
// Toggles tabs being enabled and disabled. Prevents accidental reloads.
function toggleTabs(element, tabContainerId) {
// Get all of the tabs within the tab container, specified by the tabContainerId
const tabs = document.getElementById(tabContainerId).childNodes;
// Enable every tab except for the one that was clicked
tabs.forEach(tab => {
tab.disabled = (tab === element);
});
}
// Onclick function that merges all functions into one
function tabSelected(element, tabContainerId, widgetId, url) {
renderWidget(widgetId, url);
toggleTabs(element, tabContainerId);
}
</script>
<!-- end example script -->
</head>
<body>
<div class="key">
<h1 class="heading">Key</h1>
<table>
<tbody><tr>
<td><div class="controls--container"></div></td>
<td>The external HTML. Completely customizable and controlled by you. Not part of the widget.</td>
</tr>
<tr>
<td><div class="iframe--container"></div></td>
<td>The iframe container and widget. Not editable.</td>
</tr>
</tbody></table>
</div>
<!-- The editable controls section. This section is completely modifiable to your discretion. -->
<div class="controls--container">
<h1 class="heading">Example</h1>
<div class="content">
<p>Try out this example to see how dynamic content can render. This section of controls is completely customizable by you. The example, in this case, swaps between a calendar and an event view widget.</p>
<p>To view the sample code, right-click this page and select <i>Save As: WebPage, HTML Only</i>.</p>
<p>Feel free to copy this demo, add, edit, or remove components - this is for your reference.</p>
</div>
<div id="tabContainer">
<button class="btn btn-green" onclick="tabSelected(this,
&#39;tabContainer&#39;,
&#39;renderedWidget&#39;,
&#39;https://widget.arrive.com/index.html?ui-components=map,event-calendar,checkout&amp;destination-latitude=40.7505&amp;destination-longitude=-73.9934&amp;destination-venue-id=8&#39;)" disabled="">Render Widget 1</button>
<button class="btn btn-green" onclick="tabSelected(this,
&#39;tabContainer&#39;,
&#39;renderedWidget&#39;,
&#39;https://widget.arrive.com/index.html?ui-components=map,event-list,checkout&amp;destination-latitude=40.7505&amp;destination-longitude=-73.9934&amp;destination-venue-id=8&#39;)">Render Widget 2</button>
</div>
</div>
<!-- end section -->
<div class="iframe--container">
<!-- The rendered iFrame. Anything inside this element cannot be modified. -->
<iframe src="./dynamic-rendering_files/index.html" id="renderedWidget" height="600px" width="100%" scrolling="yes" />
<!-- end iframe -->
</div>
</body>
</html>
Last updated on by David Gwizdala