Tuesday, January 29, 2013

A Journey Toward Web Components (Part 1)

A few months ago I wrote about our efforts to change the way we did page layout in Orion. Specifically, we did not want to rely on a JavaScript library to do our basic page grid, instead moving to a pure CSS solution. One of the outcomes of that effort was the necessity to write a small chunk of JavaScript code to provide an interactive splitter that would allow the user to change the layout or collapse a pane.

Recently, as a major goal of our Orion 2.0 release, we removed even more library code in order to improve our consumability and reduce our footprint. We had started out the project using dojo and dijit. But the browsers continue to add more native utilities, and we have the luxury of targeting only the most current browser implementations. It was becoming clear that we were using a smaller and smaller subset of the library, and we'd be better off using the existing browser support and small shims or other scripts as needed. Our editor had already been through this process, because it is consumed by browser tools such as Mozilla Scratchpad, where the adopter did not want to consume any additional utility libraries.

Newer versions of dojo (we were using a rather old 1.6) have refactored the library so that you only need to pull in the modules that you use. So we could solve a lot of the size problem by upgrading our library, but we had additional issues. Some of our adopters were already using dojo or dijit and wanted to upgrade at their own pace. Other consumers did not want to adopt any components that had additional dependencies. We also felt that our hybrid approach for components was causing additional complexity as we worked with different life cycles, theming, and layout approaches.

The exercise of removing our dependence on a utility and widget library was a pretty major effort, touching many lines of code in the Orion client. Our wiki page kept a laundry list of the types of changes that were needed. Much of the effort involved mechanical changes from utility functions in dojo to newer browser functions. But there were also a few widgets we were using that needed to be replaced, namely the dropdown button and its associated menu, tooltips and popup dialogs, and modal dialogs.

We built these replacements after looking around at other implementations (such as plugins in jQuery or Twitter Bootstrap), and concluding that there wasn't much we could consume without adopting jQuery or some other library. Each replacement script was at most a few hundred lines of code, and the implementations were pretty straightforward. Most of these scripts supported pretty basic, low-level UI interactions.

  • Attaching the right events (mouse clicks, keystrokes) to the DOM to get additional interactive behavior.
  • Styling (often just hiding and showing) different parts of the DOM according to user interaction.
  • Ensuring the right ARIA roles and attributes were set.
  • Managing default focus rules and keyboard traversal between fields.

On one hand, replacing just a handful of widgets and modifying all of our client code to use browser utilities instead of library utilities is a great accomplishment for this release. Colleague Anton McConville reports a 80% transfer reduction and 45% fewer page requests. I have to say there was a big happy dance when we finally closed our library independence bug.

So while I'm really happy about our move in this direction and pretty psyched to have completed such a big job, I'm left with a nagging feeling. The new code we had to write sounds like the kinds of things the browser should handle as UI components mature. So who's to say we won't be removing all these new implementations next year in favor of something different? Can we isolate this behavior so that our page markup is relatively stable and our JavaScript not sprinkled with API calls that we keep changing with the tides?

There are also some interesting technical questions surfacing during this exercise. If most of the replacement widgetry is described by HTML and CSS, and we are just tacking on some live behavior, who owns the HTML template? The application or the widget? For example, if I want to add splitter thumb behavior in the JavaScript, can my JavaScript splitter code add a splitter thumb node to the client DOM? Or does the client's markup have to include it? Folks coming from widget libraries are used to configuring things in API, and giving the widget more leeway in changing the native structure. Folks coming from pure HTML might consider it the client's job to know what nodes are needed in the template. As soon as we start trying to consistently address these issues, it starts to sound like we're building our own custom life-cycle and widget framework definition.

Then there's the matter of consumability. I've been struggling with what to call these new, small piles of code. Saying "widgets" as I've done above implies a replacement library. How can we communicate that all we want to do is add small bits of interactive behavior to the DOM that will hopefully be made obsolete by the browser someday? How can we share these small bits of behavior?

We are thinking the answer lies in W3C Web Components. Having completed this exercise of extracting widgetry and pushing as much definition as possible up into the DOM and CSS, we believe that the ultimate shape of this code should be custom DOM elements with rich interactive behaviors. So stay tuned. We've got a release to finish, but very soon we'll report back on efforts to implement one of these small bits of interactive behavior, such as our splitter, as a Web Component Custom Element.