Saturday, July 27, 2013

The next big thing on the web – custom HTML elements

If you are either a HTML component vendor or ever wanted to use someone else's HTML module, you already faces the same issue: components may not work together and even if they do, they put a lot of noise in your pure HTML structure. This is going to change very soon.

Large component vendors like Kendo or Telerik are creating amazing HTML components that are, in theory, just plug and play: whatever framework you are working with it should be really easy to use those enhanced modules. However, even if they work as they are intended to, they change and litter the HTML DOM so any kind of debugging can be a bit of a pain.

Noisy HTML

The problem is that even if we start with a nice and clean HTML code that looks like this:

<select id="size">
<option>S - 6 3/4"</option>
<option>M - 7 1/4"</option>
<option>L - 7 1/8"</option>
<option>XL - 7 5/8"</option>
</select>

the frameworks will turn this into a lot of different divs and spans to be able to apply the nice visuals on it. However, this will create unexpected nodes and structures in your HTML code which may or may not display correctly after applying it. The above will be replaced to this during runtime (some attributes are removed for readability):

<span class="k-widget k-dropdown k-header" unselectable="on" …>
<span unselectable="on" class="k-dropdown-wrap k-state-default">
<span unselectable="on" class="k-input">S - 6 3/4"</span>
<span unselectable="on" class="k-select">
<span unselectable="on" class="k-icon k-i-arrow-s">select</span>
</span>
</span>
<select id="size" data-role="dropdownlist" style="display: none;">
<option value="S - 6 3/4&quot;" selected="selected">S - 6 3/4"</option>
<option value="M - 7 1/4&quot;">M - 7 1/4"</option>
<option value="L - 7 1/8&quot;">L - 7 1/8"</option>
<option value="XL - 7 5/8&quot;">XL - 7 5/8"</option>
</select>
</span>

Custom elements

Even though the custom HTML elementdefinition is still just a W3C draft and basically none of the browsers are natively supporting it (ChromeCanary and Firefox has a partial support), it's still by far the most interesting upcoming HTML feature I've seen in a while.

With custom elements, you can define a custom tag and add any HTML or Javascript rendering within it – the browser will interpret that locally but won't be visible from the outside. The only requirement is that the tag must contain a dash so the name will never interfere with upcoming standard HTML tags (eg: <hello> is not a valid custom tag but <adams-hello> is).

Defining custom elements

To define a custom tag, it has to be declared in the following format:

<element name="adams-hello">
...
</element>

The rendering is a bit tricky though: just because we have some internal content it will not be visible from the outside. In the above case “...” will not be rendered when someone uses the <adams-hello></adams-hello> tag. In some cases it can be a bit confusing but it's for the greater good: any internal structure can be pre-stored and used when necessary, no need to fiddle with what and what's not visible: anything that we have not explicitly rendered with Javascript is not visible.

Displaying time

To continue with our simple extension above, let's add some simple rendering to it to display the current time:

<element name="adams-hello">
<section>
Hey, the time is:
<time id='currentTime' />
</section>
<footer>It will not be visible</footer>
<script>
      var el;
      function tick(){
              el.innerHTML = (new Date()).toString();
      }
      if (this !== window) {
            var section = this.querySelector('section');
            this.register({
                prototype: {
                        readyCallback: function() {
                              var root = this.createShadowRoot();
                              root.innerHTML = section.innerHTML;
                              el = root.querySelector("#currentTime");
                              setInterval(tick, 1000);
                        }
                }
            });
      }
</script>
</element>

The code is pretty straightforward, however, there are couple of things that are good to know about:
- We need to register for the readyCallback to do any kind of rendering. Without that the element won't display anything.
- If we want to hide the internal content of the DOM from debuggers we can create a shadow root. This is not really supported yet so the root element can be simply this. In that case the internal structure will appear in the DOM (note: even if we use shadow root the browser knows about it and can display it to the developer is we enable that option – it's not for security, more for easier debugging).
Without shadow root - Chrome will display internal structure


With shadow root - nice and clean markup


You can grab the full source code fromhere. Remember to run the samples on a local web server (like python -m SimpleHTTPServer 8080) otherwise the HTML import won't work.

How can I use it today?

As basically none of the browsers support is yet so the only solution is to use some kind of polyfill framework to “bring the browser up to speed”. The only reasonable implementation I've seen is Google's Polymer Project. The framework is pretty well written so even Internet Explorer will be able to work with most of the features mentioned above (note: for me shadow root did not work). Give it a go and be prepared: this is really an exciting feature in HTML!

No comments:

Post a Comment