How QuickUI controls use code to specialize the handling of their content (in ways that might not be supported by Web Components)

As indicated in the earlier overview comparing QuickUI and Web Components, one significant difference between the two frameworks is that QuickUI allows code to run when a control’s content() property is set, while the Web Components spec does not currently allow for this. This post will attempt to begin making the case for the need for this feature, starting with an analysis of how that feature is used in QuickUI controls today.

The largest public body of QuickUI controls is QuickUI Catalog, which as of this writing includes 76 open source controls that handle a variety of common user interface tasks or serve as demonstrations of how to achieve common behaviors in controls. Of the 76 published controls:

  • 32 controls include code that runs when their content() property is set. Since the base Control class already provides a default content() property, these controls are overriding that base implementation. (In some cases, like PopupSource, the class’ content() property override is itself overridden by a subclass like ComboBox.)
  • Of the above 32 controls, 23 use their content() property override to delegate content to a sub-element. This is the standard approach in QuickUI for a control to incorporate content from its host. (For a working example, see this jsFiddle, in which a UserTile control delegates its content to a span inside the control. This topic is also covered in the second portion of the QuickUI JavaScript tutorial.) This is roughly analogous to what Web Components spec accomplishes with the proposed <content> element.
  • 12 controls (of the 76 in the catalog) are text box variations that delegate their content() property to a text box: either an <input> element of type “text” or a <textarea>. For example, the content() of a ListComboBox will be placed inside an <input>. Historically, HTML input fields have insisted on handling the field’s value through a string “value” property, whereas an element’s content is a DOM subtree. Despite the difference in data type, in many cases the distinction between “value” and “content” feels somewhat arbitrary. The convenience of a content property is just as interesting to a control that wants to render that content in a text box. For example, if a combo box is going to hold a list of animal names, it’s nice to be able to set the default content of that combo box in markup as:<ListComboBox>Dog</ListComboBox>. Naturally, this translation is lossy: if one passes a DOM subtree into such a control’s content() property, it’s to be expected that it will only preserve the subtree’s text. Nevertheless, it is highly useful to be able to define controls that render their primary content in text boxes.
  • 20 of the controls override their content() property to perform work whenever the content changes. The following table summarizes these 20 cases:
Control When content() property is set, the control…
AutoSizeTextBox Recalculates its own height to match that of the content.
ColorSwatchButton Transforms a string color name/value into a color.
ColorSwatchTextBox Transforms a string color name/value into a color.
HighlightEffects Recalculates its height/width.
HintTextBox Shows hint text if the content is empty.
Menu Recalculates the width of a subelement (a “shield” element that must be exactly as wide as the content to achieve a particular visual effect).
PackedColumns Recalculates its layout.
PanelWithOverflow Recalculates its layout.
PersistentPanel Checks to see whether the panel should be docked or not.
PopupButton Adjusts its layout if the content is not empty.
Repeater Copies the content into the array of repeated sub-controls.
SearchBox Enables its search icon if the content is not empty.
SlidingPages Recalculates its height/width.
SlidingPagesWithDots Updates the number of page buttons to match the number of pages (i.e., child nodes) in the content.
Switch Determines which child should be visible.
Tab Lets the parent tab set know the tab’s size may have changed.
TabSet Creates a tab button for each tab page.
TextBox Generates a programmatic “change” event.
TextCondenser Determines whether the text should appear condensed to help it fit.
ValidatingTextBox Validates the contents.

To summarize, these controls are doing the following types of work when their content changes:

  • Adjust its dimensions or the dimensions of some subelements (e.g., AutoSizeTextBox, Menu).
  • Layout contents to achieve results not directly supported in HTML and CSS (e.g., PackedColumns, PanelWithOverflow).
  • Transform or manipulate the content before rendering it (e.g., Repeater, ColorSwatch).
  • Update its own subelements based on the content (e.g., TabSet, SlidingPagesWithDots).
  • Validating content (e.g., ValidatingTextBox, and its subclasses like DateTextBox).

Such controls represent a significant percentage of the QuickUI Catalog — approximately 25% — and it’s very likely that similar results would be found in other QuickUI-based projects. And in addition to the scenarios listed above, other scenarios likely exist in which a control wants to perform work when its content changes.

Overall, this pass through the QuickUI Catalog suggests that many interesting user interface components have a need to perform work when their content is set — to do something more than passively hold the content they’re passed. At this point, it’s not exactly whether the aforementioned QuickUI controls could be successfully ported to Web Components as the spec currently stands, which would be unfortunate. (As stated in the previous post, a long-term vision for the QuickUI framework is that controls created in QuickUI can be transitioned to a Web Components foundation in the future.)

It’s possible that a component could use forthcoming support for DOM mutation observers could be used to track changes to its own content, but whether this would work, or work well, is not yet known. A control could also force its host to invoke some method on the control whenever the host changes the control’s content, but that would be unfortunate; it would place extra work on the developer, and a host’s failure to properly notify the control that its contents have changed could lead to subtle bugs.

A vision for coevolving QuickUI and the emerging Web Components standard

This post is the first in a series looking at the relationship between QuickUI and Web Components. This post will kick things off by laying out some basic points of a vision for how these two technologies might co-evolve.

The Web Components effort spearheaded by Google is a vital effort towards promoting component-based user interface design for web-based apps. Componentized user interfaces may radically transform the web industry. It will take some time for the spec to be finished and agreed upon, and then still more time for the technology to make its way into users’ hands. It is hoped that QuickUI can serve as a bridge to the world of Web Components, act as a reference point for work on the emerging spec, and provide services and component libraries that speed the creation of Web Component-based apps.

QuickUI and Web Components have the same goal

Both frameworks address the same fundamental objective: let web designers and developers create better applications faster through the creation and use of modular, reusable, and extensible user interface elements. QuickUI calls such elements “controls” and the Web Components spec calls them “components”, but in this context the terms are essentially interchangeable.

There are obviously differences in approach. QuickUI is built on JavaScript and jQuery, while Web Components is native code and browser- and library-agnostic. The Web Components framework, by virtue of being part of the browser, can do many things which a JavaScript library like QuickUI cannot. There are some obvious performance benefits to doing things in native code. It’s also possible for the browser to enforce a high degree of component isolation by preventing a Web Component’s host from knowing what’s going on inside the component. Such isolation is crucial for a component platform, because it leads to a proper separation of concerns. A component author can make many modifications to the inner workings of a component without fear that hosts of that component are inappropriately depending on a particular implementation. QuickUI can only maintain such separation of concerns by convention and by proffering services that make it easier for developers to use controls in a modular way than not.

Despite their differences, fundamentally these two web user interface frameworks are more compatible than not. This opens up the possibilities which follow.

QuickUI and Web Components should be interoperable

Based on the current Web Components spec, in theory it should be straightforward for a QuickUI control to host a Web Component, and vice versa. That can provide a degree of future-proof resiliency to a team that wants to build with QuickUI today. But it should be possible to do better than that…

QuickUI itself will someday be built on top of the Web Components foundation

Given the performance and modularity benefits of Web Components, and the reasonably close alignment of goals, it appears that it should be possible to eventually have QuickUI controls be Web Components.

Currently, the lowest levels of the quickui.js runtime provides services such as creating control subclasses and instantiating controls. These low-level services would be provided by a Web Components-enabled browser instead. The QuickUI runtime could potentially detect whether the user’s browser supports Web Components and, if so, create controls as Web Components wrapped by jQuery. On legacy browsers (all today’s released browser versions, going back to IE 8), the QuickUI runtime would continue to create controls as regular DOM elements wrapped by jQuery.

QuickUI can provide useful features beyond those which have been standardized

Standards, by their nature, advance slowly. Even once QuickUI is built on top of Web Components, QuickUI can continue to evolve at a faster pace to meet the needs of web designers and developers. QuickUI can be the “running code” in the maxim that Internet standards evolve from Rough consensus, running code.

QuickUI is also designed explicitly for jQuery developers, whereas the Web Components spec must be library-agnostic. In the same way that jQuery developers currently find it much easier to write an interactive UI in jQuery than by doing direct DOM manipulation, they will also find creating controls (components) easier in QuickUI than using only the low-level services offered by the browser. For example, a QuickUI control is already a jQuery instance, so a developer can immediately and directly manipulate a control using all the facilities in jQuery. As another example, QuickUI’s services for creating properties generate jQuery-style getter/setter functions which are automatically chainable, and can be applied to a collection of elements in a single call.

QuickUI may serve as a reference for work on Web Components

As a 4+ year-old web user interface framework, there’s already a considerable degree of hard-earned knowledge baked into the QuickUI framework. These lessons can be considered as the various parties working on Web Components flesh out the details of that spec. It’s in this role of QuickUI as a reference point that some of the important lessons from QuickUI will be covered in future posts on this blog.

QuickUI lets teams create componentized web user interfaces today

Many of the benefits of building a user interface with components can be achieved by a team using QuickUI today. As summarized on the QuickUI home page, those benefits include the abilities to:

  • Better organize and maintain UI code.
  • Use custom controls to provide optimized user interactions or a particular visual aesthetic.
  • To begin developing, in the course of one project, a library of reusable UI that can accelerate a team’s future projects.
  • Share common UI solutions across teams and organizations so those solutions don’t need to be created from scratch each time.

Investment in QuickUI apps today can be preserved when Web Components arrive

This is a vision, not a legal commitment. The Web Components spec is still in flux and evolving entirely outside the control of anyone working on QuickUI, so it’s impossible to promise how things will work in the future. Still, it’s plausible that a team could begin creating a web user interface in QuickUI today, and as Web Component-enabled browsers arrive and gain use, the team could automatically (or, at least, easily) transition to that better foundation to improve the performance and reliability of their apps.

The QuickUI Catalog will evolve into the web’s best open library of reusable user interface components

To an extent, the QuickUI Catalog of common, ready-to-use controls is somewhat independent of the underlying QuickUI foundation. At the most abstract level, these are user interface patterns that can be found in many applications on many platforms. Even if obstacles prevent QuickUI controls from being built as Web Components, the existing JavaScript code base for the Catalog would give one a huge headstart in creating an equivalent library of Web Components. And if the vision outlined here comes to pass, the Catalog’s collection of components — and user interfaces built with them — should be able to transition smoothly to a Web Components foundation.

Next steps: investigation of framework differences

While the above points lay out a vision for the coevolution of QuickUI and Web Components, many details remain which must be investigated before such a vision can come to pass. While the goals of the two frameworks are generally aligned, the design principles underlying the two have significant differences. For example, QuickUI’s core design principles seem to place greater emphasis on extensibility — creating a new control class by extending an existing class — than does the current Web Components spec. Such differences could lead to irreconcilable incompatibilities, which would represent lost opportunity.

The hope is that any issues can be teased out of the Web Components spec early enough and either worked around or submitted for consideration so that they may hopefully be addressed. Some key issues warranting further investigation are:

  1. A significant fraction of QuickUI controls override their base class’ content() property setter function in order to perform work when a host sets a control’s content. This is done for a variety of reasons: to partially fill in a component’s DOM tree (a sort of user interface currying); to transform content before displaying it; to recalculate layout; or to perform other operations dependent upon the content. This is not currently supported in the Web Components spec. An analysis of the QuickUI Catalog controls on this topic is underway to produce a set of common use cases.
  2. A QuickUI subclass maintains an is-a relationship with its base class. The <shadow> element in the Web Components spec may lead to subclasses that effectively maintain more of a has-a relationship with their parent class. It’s not immediately clear, for example, how one could define a base class and a subclass that meet all these conditions: a) both use the same root element (e.g., <button>), b) both are independently instantiable, c) the subclass can host base class elements (e.g., via <shadow>), and d) the subclass is a JavaScript instanceof (is-a) of the base class. These conditions often arise when extending an existing control class, and QuickUI control classes can meet all of them.
  3. The Web Components proposal minimizes the impact on the HTML language itself, but one repercussion of this appears to be that component classes can’t define custom properties that can be set through markup. As currently understood, the spec calls for hosts to pass values to components exclusively through a single content tree. The component class must then prise apart this content through a “select=” attribute so that it can incorporate content subelements into different parts of the component.This is roughly analogous to the way command-line apps must parse their text arguments, with both the flexibility and the potential for great inconsistency that go with that. In this context, such flexibility may create significant complications for the creation and maintenance of subclasses, as varying levels of the class hierarchy impose different demands on the content. Overall, this doesn’t feel as specific or clean as the compound property syntax in a language like XAML (or QuickUI Markup), in which a control class can define custom properties that may be set as string attributes, through nested subelements, or through property setter functions.

As these issues are investigated more deeply, the results of those investigations will be posted here.