ING ❤️ Web Components

Over the last several years, the increasing popularity of component-based architecture for web development massively changed the way developers built user interfaces. This model moved away from the more traditional MVC approach to UI development by chunking up interfaces into (you guessed it) components!

Component-Based Architecture

The way CBA (Component-Based Architecture) works is to separate the parts of your interface into their own independent components, putting an emphasis on reusability and single-responsibility. An interface can consist of different types of components: from simple “leaf” components like buttons or inputs, to more complex compound components such as a log-in form, which itself consists of a number of other components.

A simple UI button component, used as: <ing-button>

In this way entire features like app views can be defined as their own components, while consuming and reusing simpler components.

A Direct Debits feature component, used as: <ing-orange-direct-debits>

So how exactly do Web Components play into this?
Web Components are a set of unified web standards that allow us to write the kinds of components we’ve been discussing in a way that should work across browsers and frameworks.

Historically, there were a few attempts of standardizing a component model in the past, like Microsoft’s HTML Components (HTC) in 1998 and Mozilla’s XML Binding Language (XBL) in 2001. The first public draft, called Web Components v0 for the modern Web Components standards was published in 2012. In 2014, Chrome and Opera added support for the v0 spec. In 2016, the v1 spec was published, reflecting the consensus reached among browser vendors over the features and APIs of web components.

Although the browser standardization process takes some time, once accepted, browser standards tend to ensure longevity.

ING ❤️ Browser Standards

So let’s take a look at the standards that allow us to write Web Components:

  • Custom Elements:

The Custom Elements specification enables us to define and use new types of DOM elements in a document. We’re basically telling the browser, “Hi browser 👋, here’s a new kind of HTML element, and here’s what to do with it!”.

  • ES Modules:

The v0 web components specification provided HTML Imports as the standard way to publish components and import them into our projects. Sadly, that specification failed to gain traction among browser vendors, so it was deprecated.

Meanwhile, JavaScript Modules were standardized and implemented across browsers. Since they provide browser-native to share reusable and self-contained bits of code, it was a natural fit for web components.

  • HTML Templates:

The HTML Templates specification lets us write reusable chunks of DOM. A HTML Template is a content fragment, and it’s contents will not be processed by the parser until we tell it to.

  • Shadow DOM:

Shadow DOM allows us to encapsulate the markup and styles in our Web Components; anything inside a shadowRoot will not be affected or overwritten by styling from outside, and none of our styling will leak outside our components.

ING ❤️ Browser Support

With Edge announcing their intent to adopt the Chromium engine, soon all major browsers will natively support Web Components 🎉.

Fortunately, Web Components are fully polyfill-able, which allows us to achieve backward compatibility for older browsers that don’t natively support Web Components, such as Internet Explorer. This can, however, make polyfilled browsers performance slower.

ING ❤️ Practical Demos!

Alright, enough talk of standards and specifications, time to get our hands dirty and look at some code!

Here’s an example of how we could write a very simple Web Component:

We can now simply use our component like so:

And it’ll show up in the DOM as:

A common misconception about Web Components is that they can only take string attributes to pass down data. While it is true that attributes can only be strings as a limitation of the HTML specification, fortunately, we can simply implement getters and setters if we want to pass down some rich data like objects and arrays like so:

And we can then set the property using javascript:

Excellent, we now have a fully functioning Web Component! And what’s great about this is that this code will run in any* modern browser, you can copy and paste this code into your browser’s console, add the <ing-demo> tag to your HTML, and it'll work! More so, we can now consistently use the same component across all of our applications.

* Edge once they’ve switched to chromium, expected early 2019

What’s less great about this is, is that writing code like this will very quickly become tedious, hard to read, and hard to maintain. Imagine if we have a component that has 10 possible properties. We’d have to write 10 getters, 10 setters, and what if we want to reflect our properties to attributes as well? That’s going to be a bunch of work, and a whole lot of boiler plate code. Web Components are low level by design, and intended as a collection of standards that do very specific things that the platform didn’t allow yet. So that means we might need some type of abstraction that makes all this easier for us, and this is exactly why:

ING ❤️ The Polymer Project

Not only has Google been one of the main driving forces for Web Components, they also provide excellent libraries that help us create them. For a long time, the Polymer library was the synonym for Web Components, and played a major part in the adaptation of Web Component usage.

Now that the standards have matured, it has become much easier to develop Web Components, and many libraries and frameworks now support both the creation and consumption of Web Components, such as:

If you’re interested in using Web Components in your favourite framework, you can visit custom-elements-everywhere. Most frameworks* support the consumption of Web Components without any hiccups.

* Sadly, React requires a few extra steps to make Web Components work, since it cannot listen for DOM events coming from Custom Elements without the use of a workaround, and will pass data exclusively in the form of attributes, and not properties.

At ING, we ❤️ to use the Polymer Classic library and the new LitElement and lit-html libraries for developing our Web Components. Let’s take a look at how we would rewrite our <ing-loves>component using LitElement:

LitElement’s static properties getter makes it incredibly easy to manage both our properties and attributes, and makes it easy to declaratively render our HTML. More so, we just went down from 35 lines of code in our original example, to a measly 14 lines of code.

ING 💔 Bugs

Although Web Components have been around for a little while, many JavaScript libraries or browser extensions don’t support websites built with Web Components. Most of the time, the reason for this is that many extensions or libraries are not built with Shadow DOM in mind. If you need a refresher; Shadow DOM allows us to encapsulate our components. In some sense this is great, because it means that Shadow DOM is doing it’s job correctly, but it’s also a disaster because we love to use our favourite extensions! Fortunately, this is mostly a matter of time; as Web Components gain more and more traction, more and more libraries and extensions will start supporting Web Components.

Some time ago, we experienced a similar type of problem where the Custom Elements polyfill didn’t play nicely with the LastPass browser extension. This lead to users being unable to use the LastPass extension to log in to our banking application.

ING ❤️ The Future

Web Components have *almost* been adopted in every major browser, but that certainly doesn’t mean the end of it. There are many more exciting specifications and features to be added that will only increase the benefits of using Web Components. Here’s a short list of what to look forward to in the future:

A valid criticism against Web Components is that Custom Elements are defined in a global registry, which could cause name collisions and all kinds of trouble. Scoped Custom Element Definitions allow the ability to construct CustomElementRegistries, and use a given Shadow Root as a scope for those definitions, making it easy to avoid name-clashes.

Shadow DOM is great for encapsulating our styles and markup, and protect it from being overwritten by any outside styling. But… what if we actually want to overwrite some styles? The CSS Shadow Parts specification allows us to style purposely exposed elements in a shadow root from outside of the Web Component.

The Accessibility Object Model aims to improve browser APIs for assistive technology. Currently, Web Components are forced to use ARIA to declare their default semantics. This causes ARIA attributes which are really implementation details to “leak” into the DOM.1 The Accessibility Object Model specification makes it easier to specify accessibility attributes and properties for our Web Components, and ultimately allow our Web Components to be more accessible for our users.

As a bank, it’s not only important that our applications work in any browser, it’s also important that our applications are accessible for all of our users. If you’re interested in accessibility, stay tuned for a blogpost on accessibility by our own accessibility guru himself: @erikkroes!

And many, many more great additions are being added to a browser near you! Some honorable mentions: Template Instantiation, HTML and CSS Modules, and Constructable Style Sheets.

That’s all, folks!

👊
🎤

That’ll be all from me for this blog post, I’d like to thank you for reading, and if you have any questions about Web Components, or if you have any feedback, criticism or questions, feel free to reach out on Twitter. I’d also like to thank Benny Powers from Forter for taking the time to review and his helpful comments and feedback ✌.

Additional Resources

If you’re interested in some more technical and hands-on blogposts on Web Components, you can check out: