Designing a Highly Reusable HTML Component

The UF College of Education uses a header/footer template designed to be applied to any page, and we use this across several applications such as WordPressMoodleElgg, and Drupal. Changes can be propagated quickly to all sites, and adding the template to new PHP apps is trivial.

If you need to create an HTML component that can be reused across a wide set of sites/apps, these guidelines might help.

Avoid HTML5 elements if you can

HTML5 elements like header must be accompanied by JS to fix compatibility in old browsers. Sticking to HTML4 also helps with validation under HTML4/XHTML doctypes. Of course, if you’ll only be deploying to HTML5 sites that already have the IE shim, go ahead and use the best markup elements for the job.

Guard the host markup against the component CSS

Any component CSS selectors that match host markup elements can cause massive problems in the host application, and if this component is applied across an entire site, it’s very difficult to predict the impact. The key then is following a few simple rules for the component CSS:

  1. Each class/id name must be sufficiently unique such that there’s practically no chance of name collision. Unfortunately even selectors like .hidden and .clearfix could be implemented in different ways in the host app and this could cause problems. Using a constant prefix in every name might help.
  2. Each selector must include at least one of the component classes/ids.
  3. Avoid using a CSS reset/normalizer. If you must, make sure each selector follows the above rules so the effect of this is limited in scope to the component.
  4. Selectors must not match non-component elements. E.g. the selector #component-root + div should not be used because it would select a DIV element after the component.
  5. Take care to avoid obscuring elements in the host page. E.g. negative margins could pull the component over a host element.

Guard the component markup against the host CSS

Similarly, host CSS could break the desired styling of the component markup.

  • Test the component in a wide variety of pages and applications. Especially test pages that use common CSS resets and normalizers, and that have a lot of element-only selectors in the CSS.
  • When interactions occur, make the affected element’s selector more specific until the component CSS “wins”. As always, test across the browsers you need to support; IE7 still has some specificity bugs for the selectors it understands, if you need to care about that.

Javascript Tips

Expose as little to the global namespace as possible

E.g., define all necessary functions and variables inside an anonymous function that is executed:

!function () {
  // your code here ...

  // explicitly expose an API
  this.myComponentAPI = api;
}();

Document your script’s dependencies and let the implementor supply those

Automatically including JS libraries may break the host app. Consider the case of jQuery: Many plugins extend the jQuery object, so redefining it removes those added functions (actually stores them away, but it will break the host app nonetheless). Don’t assume the user did this right. Wrap your functionality in a condition that first tests for the presence of the the library/specific features you need, and make it easy for the implementer to realize the problem if they have a console open.

Here’s an example of how to test for jQuery’s on function:

if (this.jQuery && jQuery.fn.on) {
  // code
} else if (this.console && console.log) {
  console.log('Requires jQuery.on, added in version 1.7');
}

Assume the component could be embedded after the page loads, and multiple times

Carefully consider the initialization process your component requires. In some cases it’s reasonable to leave the initialization to be triggered by the implementer. If you do automatically use DOMReady functions like jQuery’s ready(), consider allowing the implementer to cancel this and initialize later.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.