Web components are the great hope of the future of web apps. It seems to have taken forever to get a start on such a basic technology and we don't seem to be there yet. Mozilla's X-Tag is a library that aims to get you ahead of the curve.

X-Tag is a way of creating web components before the majority of browsers support the new standard. The good news is that it uses standard JavaScript polyfills to implement something reasonably close to the Web Components standard. As more browsers support the standard the library can take this into account and so your web components can work in the new more efficient way without you having to do much about it.

This is the theory but it all depends on X-Tag being kept up-to-date and Mozilla has a track record of just letting projects fizzle out.

In this case, however, X-Tag is the basis for a more headline-hitting library - Brick. This provides a range of fairly sophisticated web components using X-Tag as its implementation library. This at least suggests that X-Tag might continue to be developed for a while longer at least.

W3C Web Components

So what are web components?

Most JavaScript programmers have been aware of how to create a web component for a long time. It is just a new UI component that is built up using existing HTML elements - a calender, graph, gauge, progressbar and so on. By manipulating the DOM using JavaScript you can create whatever you want.

There are already formalized ways of doing this job. For example, jQuery UI provides a lot of web components that you can use Getting Started With jQuery UI and a framework for you to add your own custom components jQuery UI Custom Control - Widget Factory. Now there is a W3C standard for creating Web Components and it goes well beyond what the alternatives offer and builds the idea into the browser. It goes further because it provides ways to make your custom controls more efficient and it allows others to use your controls as new HTML tags.

The problem is that at the moment support for the standard is still evolving - in fact there are parts of the standard that are still evolving.

X-Tag makes use of the Polymer library of HTML polyfills to emulate the custom element, HTML imports and mutation observers. If you already know about the Shadow DOM, you might be surprised that although it is an aspect of the new standard it doesn't make use of it. It's cool but it isn't actually needed.

The W3C Web Component specification consist of five areas of development:

Templates, which define chunks of markup that are inert but can be activated for use later.

Decorators, which apply templates based on CSS selectors to affect rich visual and behavioral changes to documents.

Custom Elements, which let authors define their own elements, with new tag names and new script interfaces.

Shadow DOM, which encapsulates a DOM subtree for more reliable composition of user interface elements.

Imports, which defines how templates, decorators and custom elements are packaged and loaded as a resource.

Of these only Custom Elements are actually central to creating custom components. X-Tag provides access to custom elements, templates and imports. But it makes sense to start on the big story and concentrate on custom components.

First how W3C thinks it should be done.

You can define a new component either in script or declaritvely using the element tag. New components can have arbitary names but they have to include a hyphen.

To do the same job in code you would need to use the document's register method:

document.register("my-component", {prototype:prototype object for the component});

Obviously, the prototype object contains code which does all of the work in creating and running your new component. The register method also returns a constructor for your new component.

Once you have registered your component you can use it just as if it was a standard HTML element. You can create an instance using:

<my-component></my-component>

or you can create it and add it to the DOM in the usual way:

var mycomponent = document.createElement('my-component');

There is alternative way of creating a custom component which is useful if you think that your app will be used in browsers that don't support Web Components. You can define your custom component to be a variation on an existing tag:

document.register("button","my-component", {prototype:prototype object for the component});

Now when you use the new component you have to use the <button> tag and the is attribute to specify that it is your component that is to be used. For example:

<button is="my-component"></button>

now if the browser doesn't support Web Components you simply get a standard button in place of your custom component. You can do the same thing in script:

var mycomponent = document.createElement("button", 'my-component');

If you don't specify an existing element that your component extends then if the browser doesn't support Web Components the result is an HTMLUnknownElement in the DOM.

Obviously the prototype has to have some structure to create and maintain the custom component. There are three callbacks that do most of the work:

readyCallback - called when the custom element is first created

insertCallback - called when the custom element is inserted into the document

removedCallback - called when the custom element is removed from the DOM.

Usually the readyCallback does the work of creating the custom element and always needs to be defined. The other two are often optional and give you a chance to control how your component interacts with others and to clean up and delete resources.

Obviously custom components can have any number of properties and methods as you care to define in the prototype object. They can also have attributes and these are added and worked with in the usual way. In other words once defined and created custom components work just like any other HTML element.

There is just one small difference - the definition of a custom element has to be loaded and processed before the tag or DOM object can make any sense. The idea is that custom elements are loaded and then upgraded or updated as soon as a definition can be applied. To make it possible for you to avoid working with elements that haven't yet been upgraded you can make us of the new :unresolved CSS pseudoclass.