Activable: a modern approach to UI components

Activable is a new step between current libraries of UI components and the upcoming Web Components: a lightweight, IE8 compatible script that enables to build common UI components in an entirely declarative way. In this post, I explain the rationales behind this project.

The newcomer

A few weeks ago I dived into Twitter Bootstrap, trying to understand what the fuss was all about. This project combines a CSS framework (a boilerplate CSS + a grid system + some layouts) with a library of UI components powered by jQuery and custom plugins. TB is modern in many ways:

  • it includes CSS mechanisms to build responsive designs,
  • the UI components are progressively enhanced with CSS3,
  • it ditched support for IE6 and has a good support for recent smartphones and tablets.

Despite its reduced file-size and fresher theme, the library of UI components has nothing revolutionary compared to the 5 years old and already venerable jQuery UI:

  • it depends on jQuery,
  • each component need to be initialized: $( elem ).component();

Realizing that made me cringe a little, and share my disappointment…

The declarative era

How long until we can write HTML/CSS only and have functional UI components? Let’s consider the current situation:

  • it’s 2012 and we’re still waiting for Mozilla to implement <input type="range" />,
  • Dijit (Dojo’s UI library) claims to offer declarative components, but they’ll only work if present in the document on DOMContentLoaded,
  • Web components will, in the future, give Web developers the ability to develop clean & reusable UI components (if you haven’t read the intro, I advise you to do so), but a third of our users still browse the web using IE8 or worse.
Let’s face it, I’ll have to initialize my UI using JS for the ten years to come.
…All I asked for was the ability to automatically apply a behavior to some special <div>s…
― me, one month ago

Event delegation to the rescue

All hope is not lost, for event delegation makes it possible to register a single click listener on a document, and filter the events bubbling up the tree according to their target. Using jQuery for instance, one can register a global delegated event handler in the following way:
$( document ).on( "click", "li.item", function handler() { … } );
In this case, the handler would be executed for every click inside <li> elements of class item.

Creating a declarative tab component is then just a matter of associating a behavior with some special markup:

Behavior
A tab component consists of a list of labels and content panes. When a label is selected, the associated content is displayed. The content of the other tabs in the same component are hidden.
Markup
What need to be identified in the markup are: the instance of the tab component (.tab), the clickable labels (<a>), their associated content (<div>), as well as “which tab is currently displayed” (.active). The relationship between labels and their content can be expressed using internal links.
Glue
And finally write the JS that adds and removes the .active class in a delegated click handler, and the CSS that highlights active labels and shows active content panes.

Introducing Activable

Activable is the JS glue described above.

Note that the suggested .tab class has been replaced by a generic data-activable attribute. The JS tab of this fiddle has been included to show how much lines of JS were written to create this specific demo (if it’s blank it’s not a bug).

If this components looks familiar to Twitter Bootstrap users, it’s because its CSS framework is being used in this example. In fact, it is possible to recreate many of TB’s UI components, using Activable only…

Generalization

The behavior “when one tab is clicked it becomes visible and the others are hidden” happens to be very similar to other component behaviors:

  • “When one accordion pane is clicked, it expands and the others collapse”,
  • “When one radio button is checked the other buttons are unchecked”,
  • “When one branch of a tree-list is clicked, its children become visible and the other children are hidden”,
  • “When one image in a carousel becomes visible, the other images are hidden”,

This could be generalized to “When an element in a group becomes active, the others become inactive“. One simple variation of this behavior would be to allow the state of an element to be toggled, and another variation would be that state changes don’t affect other elements of the same group.

Activable implements these three behaviors and can be used to implement tab/accordion/radio buttons/checkbox buttons/tree-list and even carousel components, as illustrated in this demo.

Using and extending

Although there is no dependency on any CSS framework, there are some conventions to respect in your markup to make your UI components “activable”. Those conventions are detailed in the documentation, along with the JS API that can be used to extend the components:

  • event listeners: .on( "activate", callback ) / .on( "deactivate", callback ) / .off( type, [callback])
  • direct modifiers: .activate() / .deactivate() / .toggle()
  • iterative modifiers: .next() / .prev()

What’s next

Activable is not meant to replace Twitter Bootstrap or jQuery, it’s only here to help you develop UI components quicker and keep your code clean. If I was a marketing guy, I’d say that Activable is the Backbone of UI component libraries (with a scope currently limited to click-based interactions).

In the future I’ll develop another script for draggable, droppable and sortable components, as well as one script for hoverable components. For now, I’d really like to see some people experiment with Activable and provide some feedback about the behaviors, the conventions and the API.