Building a responsive client-side widget framework – Part 1

Share the joy

JustGiving has a rich set of public REST APIs available to the developer community but their uptake can be a challenge for many of our charity and fundraising customers who lack the technical expertise to use them. So we decided to build out a set of JustGiving widgets, powered by our APIs. These allow our data sets to be consumed widely with a simple cut-and-paste code snippet. For example, we’ve released a widget that means charities can have a leader board of their supporters fundraising pages on their site. In this two-part post I talk over the approach used to build JustGiving widgets.

The widgets needed to meet the following criteria:
– Require no technical expertise to use
– Be flexible in terms of their content and complexity
– Built from client-side technologies to minimise workflow overhead
– Have a fluid layout
– Allow users to select different configurations for their widget
– Work cross-browser and cross-device
– Lightweight and fast and leave no code or performance footprint on our users’ pages
– Be easily iterated so new widgets can be built quickly

What is a widget?

To clarify, by the term ‘widget’ I mean a piece of JustGiving functionality that can be added and displayed on an end-user, third-party website [I shall refer to this site as the ‘host’ site]. If you’ve ever used a Facebook like button on a website other than Facebook you’ve used a widget. Our initial offering of widgets will aim for simplicity, but the sky’s the limit as to which widgets we build, from leader boards and data visualisation, to mash-ups with other 3rd-party APIs.

Problem 1: Adding JustGiving functionality to a third-party webpage

There are two commonly used approaches to adding third-party code into a host webpage – DOM injection and iframes. DOM injection involves using JavaScript to inject html directly into the host page’s DOM. The advantage of this approach is that the widget becomes seamlessly part of the host page’s html structure and is inherently flexible in its layout. The disadvantage of this approach though is the exact reverse because our widget is now part of the hosts web page DOM, it is ‘open’ to manipulation by the host page’s own CSS and JavaScript which is a problem where we want to ensure consistent branding and functionality in our widgets. What’s more we are unable to use any third party JavaScript libraries in our widget because these would add JavaScript globals to the host page potentially causing havoc with the host page’s own JavaScript environment.

Iframes solve these problems because they are a ‘closed’ sandboxed environment that neither leak their JavaScript globals, nor allow manipulation of their content from outside their own domain. They give us the freedom to use in our widgets the JavaScript libraries we choose.

There’s a downside and this is that iframes are not inherently flexible when placed within the DOM. As with any browser window, if the content inside an iframe is larger than the iframe’s dimensions, scroll bars are triggered creating a poor user experience. The solution to this problem is explained a little later.

Problem 2: Simple to use

Once we have decided to use an iframe for our widget, we need a way to get the iframe loaded into the host page in a way that does not require technical expertise. To do this we provide the user with two simple code snippets to add to the source code of their page. The first is an empty html div element, with id and class attributes. This html snippet will be the widget container and is added into the source code at the point where the widget will display. Next we provide a simple inline JavaScript snippet to be included anywhere in the document, whose sole job is to load a secondary ‘host’ JavaScript file and append it to the host page’s head element. This host JavaScript file handles the logic of creating an iframe element, appending it to the container element, setting its source attribute and so loading the widget content into the iframe.

There are several advantages of using an intermediary script snippet to append a secondary host JavaScript file in this way. First we should assume that once the end user has pasted our code snippets into their page they might never be touched again. By keeping the widget logic in a separate file on our servers that’s downloaded each time the widget is loaded we are free to update this code when we need without the user taking any action – one of the inherent bonuses of the web as a platform. This secondary JavaScript file will automatically be loaded by the browser asynchronously so it won’t block the rendering of the host page at load time and keeps the performance cost of the widget to a minimum.

It’s important to keep in mind that any JavaScript code that will be added directly to the host page should be cross-browser compliant and gracefully degrade when errors are encountered. Because we don’t know where the widgets will be used we can’t make any assumptions about the JavaScript environment that the host script will be loaded into. A cut the mustard style feature detect is used in our widget host JavaScript file to cancel the loading of widgets in browsers below IE9, and relevant DOM polyfills for legacy browsers are built in to ensure cross-browser compatibility.

Problem 3: A fluid iframe

Iframes are browser windows, which we can script using the Browser Object Model (BOM) API. Although they can be inserted into the DOM they don’t behave as DOM containers do with respect to their content. A standard DOM box, such as a div will expand into its parent container and around its content unless CSS is used to set its overflow property. But iframes, like other browser windows, will handle overflow by triggering scroll bars. This is a problem for our widgets when we don’t know before loadtime what dimensions the content will take, or if we want to update the content of the widget after it has loaded. It also presents a challenge for making our widgets fluid and flexible so they can fit on any screen size, or in any box size in the host page’s layout. The solution to this was mix of JavaScript and CSS to give both fluid layout and flexible height. The content inside the iframe (the widget content) is styled to be fluid, and the iframe width is set to 100% so it always fills its parent container width. This gives the end user flexibility in how they handle its layout within their page. A widget height reset method is made available in our widget JavaScript and is called at widget load time, on window resize and arbitrarily as needed. It measures the widget’s current scroll height and sends this value, via the cross-domain HTML5 postMessage API, to its parent window (the host page). The host script on the parent window listens for messages, confirms they originate from the widget, and uses the height value passed in to them in the message body to set the height of the iframe. On window resize this function is debounced to ensure we don’t clog up the JavaScript event queue with repeated function calls. With good cross-browser support the postMessage API seems to be a good approach to making our iFrames responsive both within the wider page and to their own changing content.

You can read about the next steps in building out the JustGiving widget framework in part 2 of this two-part post.

Share the joy

About the author

Leanne T

Senior Front-End Developer

View all posts

Leave a Reply

Your email address will not be published. Required fields are marked *