Best practices for building embeddable widgets

Tags:

With all the embeddable buttons, such as Facebook like buttons, and widgets like Disqus comments and whatnot these days, you’d think there was some nice info on how they are actually built.

But it turns out no, not really. I found this first hand when we had to build some FB like button style things at work, and had to basically invent the whole process myself.

Here’s some ideas and best practices for implementing embeddable widgets in the style of FB like buttons or anything else. Some of this is based on an answer I gave on Stack Overflow on a similar topic.

Getting started

The first step is getting your widget on the other website.

The most common approach used for this is simply a short bootstrap script. A bootstrap script is simply some JavaScript code which loads the remaining assets for your widget, or you can even load the entire widget in one go if it’s not very complex.

This script should reside on your server – it can be either a static file, or dynamically generated by a server-side script.

You have two options for this:

  • Use a script tag to load the bootstrap
  • Embed an inline JS snippet to load the bootstrap

Embedding directly with a script is of course more straightforward. However, in a case where a page is server from HTTPS, it may be a good idea to also serve your script from HTTPS, as otherwise it may cause a warning in the browser that there’s “unsafe” content on the page.

In the end, the choice is mostly just up to whether you need to do some processing or not in order to embed the widget.

There’s just one rule for the embedding code: Do not put any very important logic in it.

Why? Once a user has embedded your script, assume they will never change it again. It must keep working with the embed code the user has. If you put too much logic into your embed snippet, it might require the users to update it. In order to ensure your widget works correctly, keep the embedding code as simple as possible, so that you control as much of the script as possible.

Embedding your content on the target site

After creating the script to load your widget’s code, you need to decide how you want to embed your content on the target website.

There are two ways to do this:

  • Iframes
  • Building the whole DOM of your widget in JS and placing it on the target page

The primary factor in choosing between the two is that with iframes, it’s much easier to do more complex content, but building the DOM and embedding on the target page can be more flexible for certain things. You can of course also use a combination of the two, building some DOM and displaying some content in an iframe.

When using iframes, you can essentially build the content inside it the same way you would build any website. An advantage of using iframes is also that you can use forms easily, as you don’t need to think about using Ajax or anything since the iframe is separate from the rest of the page.

However, in older versions of IE, iframes do not support background transparency, thus if you want to display your content hovering over the target page, you need to use some other approach.

Choosing what your widget will display on the target site

As many widgets’ displayed data depends on what site it’s on, or who the user is, you need to be able to tell this when adding the widget.

The most basic way to do this is of course to include some kind of an identifier in your embed code. For example, if you have customer-specific widgets in the style of google analytics or such, you can simply include the customer’s identifier in your embed script’s URL and then generate your widget’s code accordingly using a server-side script.

You can also use cookies to detect the user in some cases. If the user has visited your site or used the widget before, you can detect any cookies you placed in their browser on your domain before.

Any other features of your widget can be easily sent as parameters in the embed script’s URL as well. For example, typical use cases are customizable widgets, so for that you could simply append some GET parameters into the query string to identify the customization options.

Communication between the widget, the target page and your site

In a case where your widget needs to interact with the target page, or if the widget needs to send data to your server based on user interaction, you need to choose a suitable method for doing the communication.

The suitable methods depend on how you built your widget (iframe or DOM, or combination)

If you use iframes, communication between your widget and your server is simple, but communication between your widget and the target page can be tricky.

If you use DOM, communication between your widget and your server can be tricky, but communicatino between your widget and the target page is simple.

In order to post data to your server from your widget, the simplest way is to use an iframe. As you cannot use XMLHttpRequest in a cross-domain scenario, the iframe is a simple choice. If your iframe’s content is on your own server, you can have a script inside the iframe use Ajax, or just use a normal form post.

You can also use a form embedded directly on the target page and create a hidden iframe to send the data from it without requiring a page load.

In a case where your widget uses a combination of DOM embedded directly on the target page and an iframe, you may sometimes have to communicate between your embedded script and the iframe. In order to do this, you can use window.postMessage.

There are several things you need to keep in mind with postMessage and cross-domain messaging but those are a bit out of scope for this post. I recommend checking these two links for further information: Cross-window messaging (postMessage) and Cross-domain communication with iframes.

Rules for JavaScript code

These rules only apply for JavaScript code that you are loading on the target page. If it’s inside an iframe, it doesn’t matter that much, since it cannot interfere with the target page.

In order to create a widget which does not interfere with the target website, there are some rules you need to follow:

  • No overriding anything: Do not override built in object prototypes or functions. If you do, you risk breaking the target page’s functionality
  • No loading 3rd party scripts: Do not load libraries or other scripts unless you’re sure it will not create global variables that can conflict with the target page’s code, or you risk breaking the target page.
  • Handle your errors correctly: Be sure to be very careful and handle errors propery, as any error in your widget code can break the target page. Make sure you check for things you don’t normally check too, like errors with DOM functions which usually succeed.
  • When listening for events, always use addEvent and addEventListener: Never override any events (eg. el.onclick), as a handler may already exist for it and you risk breaking the target page

Rules for CSS styles

These rules again only apply for any CSS you put directly on the target page. CSS rules in code used inside an iframe cannot interfere with the target page.

  • You must always inline the styles you use: All styles of HTML elements you create must be inlined, because the customer’s website may have its own CSS styling for them.
  • Never trust the styles: The target page may have completely weird and wonky styles. If you’re at all unsure, inline even the most basic styles for your widget’s DOM nodes.
  • Never add any CSS rules: Adding any rules (eg. something that isn’t inlined in the style attribute) can easily break the target page

Other considerations

Some further things to keep in mind is browser support, especially for older browsers and mobile devices.

What should be displayed on the page in a browser which you don’t support? Keep in mind that some website which wants to embed your widget might still get considerable amount of traffic from some older browsers.

If you’re building more complex functionality into your widget, how does it function in a case where the user is using a mobile browser?

There is no answer to these, as it all depends on how your specific widget works, but I wanted to mention them as they are important things to consider in planning.

Conclusion

Keeping these rules in mind you should be able to develop embeddable widgets which don’t interfere with the page or cause problems.

As with all “rules” and best practices in software development, remember that there can be reasons to break them. You can treat them as guidelines, but only if they make sense in your specific case.

Have you built widgets like this yourself? Is there anything you would like to add?

Is there anything you would like some further clarification or examples on?