TL;DR: This blog provides a quick introduction to web components. A later blog will show how web components can be used on e-commerce sites, including how to address common web storefront performance issues.
Web components allow frontend developers to extend the set of available HTML tags a browser understands. For example, a <pinch-zoom-img> web component might use similar HTML markup to the <img> element, but provide additional capabilities. Any JavaScript used to implement the web component is a part of the web component definition, not the HTML page markup.
How to Define a Web Component
Web components are defined using JavaScript. Any frontend developer can create their own web components. They can be included with a specific project or created as a library to be shared across projects.
Web components should not be confused with React/Angular/Vue/etc components. These technologies also have a component model, but are used to build a document, not extend the markup that can appear in the document. That is, web components operate at a lower level, extending the set of node types the browser understands in a HTML document.
For example, AMP includes the <amp-img> web component. This component has built in logic to predict the best time to download the image (e.g. lazy load images below the fold). This helps optimize network usage as images that are going to be visible are downloaded before images that will not be visible until the user starts scrolling. The rules involved are somewhat complex and can change over time (e.g. a wifi connection may be more aggressive in downloading images than a 4G connection), so capturing them in a reusable web component makes sense. The content just says it wants an image displayed — the web component definition contains the complex logic, which can be updated anytime if a better algorithm is determined.
Note that web components must include at least one hyphen in their name, guaranteeing HTML can introduce new element names without risk of colliding with web component names used on a page, which could result in broken documents.
Shadow DOM vs Custom Elements
If you are not a JavaScript expert, you may have come across terms like “the shadow DOM” and “Custom Elements” but wondered what they are. These are lower level capabilities that are relevant to build a web component. (“DOM”, the Document Object Model, is the in memory tree representation of a parsed HTML document.)
- Custom elements are defined by a W3C spec that is being merged into the core DOM and HTML standards. The API allows JavaScript developers to register new DOM element names, such as “pinch-zoom-img”.
- Shadow DOM allows a DOM to be created inside a document where CSS classes of the main document do not affect the nested DOM, and vice versa.
Custom elements are clearly a core part of defining a web component. They are what makes it possible to register a new DOM element name for use in a page. When you load the JavaScript for a web component (AMP frequently uses via a <script src=…> tag in the <head> element), it normally includes JavaScript such as the following to register the new web component.
window.customElements.define('pinch-zoom-img', ...);
The idea of the Shadow DOM is that it allows a component developer to have internal DOM nodes and styling that is not affected by and does not affect the main document’s CSS. This is good for modularization. A component can use the full gamut of HTML markup and styling without concern of interference with the rest of the document (e.g. CSS class names will not collide).
At the same time, the Shadow DOM isolation model is also problematic if you want to support style changes. It is impossible to style a shadow DOM tree via the global site’s CSS file. There are efforts underway to see if there is a happy middle ground where the main document can control some, but not all, of a web component under the control of the component author.
To learn more about web components and and easy way to create them, check out LitElement from Lightning-fast templates & Web Components: lit-html & LitElement. To show how easy it can be to create a web component, here is a complete working example of a web component from the LitElement project:
import { LitElement, html, property, customElement } from 'lit-element'; @customElement('simple-greeting') export class SimpleGreeting extends LitElement { @property() name = 'World'; render() { return html`<p>Hello, ${this.name}!</p>`; } }
In a document you then refer to a web component using declarative markup, such as
<simple-greeting name="Everyone"></simple-greeting>
Obviously most web components would be more sophisticated, but it shows how easy it is to declare your own.
Performance Benefits of Web Components
Are web components faster than dropping JavaScript directly into a page? I do recall reading a discussion on the technical merits of web components as they were implemented inside the browser, increasing the opportunities for multi-threaded processing and more. So there are technical benefits.
However, what I personally find more compelling is that web components allow an organization to use their more skilled JavaScript developers to build components for the rest of the team to use. The other developers do not require any JavaScript knowledge to use the component, which can help reduce staffing costs without sacrificing site performance.
Further, if a project goes as far as eliminating most/all JavaScript from web pages, then maintenance can be easier as most performance impacting JavaScript code will be clearly delineated from the page contents. It is straightforward to perform audits for non-performant JavaScript if pages only contain references to web components with no or minimal JavaScript on the page. This also makes it safer for changes to be made to a website by developers who were not involved in the original site build. Thus web components offer a way to help enforce process discipline regarding JavaScript on a site.
Why Web Components vs Not React et al?
Most of the above benefits could be argued to be true for React/Vue/Angular etc as well. They also support components where experts can build components for others to use — they are just not web components.
This is where judgement comes in. These frameworks deliver great results without web components. But there is no single “always best” solution. For example, a benefit of web components is that they can work on any site – they are not tied to a specific toolchain.
Finally, it is also worth noting that you can use web components with these frameworks. React can assemble a DOM that includes web component markup. You can also potentially use these frameworks to build web components, although one must be careful here not to lose the benefit of components being lightweight.
Conclusion
This purpose of this blog was to give a quick introduction to web components. They are relatively simple to create and can result in HTML pages that are easier to read and maintain.
While I am not recommending that all projects immediately move to web components, I do believe they are worth understanding. This is not with an eye to guarantee top performance of every site, but rather as a way to support a development process that should deliver good results on most sites with more junior developers.
For example, a library of web components can be used on any site. A library of React or Vue components mandates the project use React or Vue. For myself, with a goal of supporting web e-commerce across multiple platforms, web components are particularly interesting as they are not tied to one platform – a library of web components can be used by all platforms.
But above all, I really like the simplicity of pages that comes as a result. I put forward the less JavaScript there is on a HTML page, the easier the page is to maintain. But more on that in a future post.