Recently, I wrote an article about how to build your first Web Component and some history and explanations about the basic v1 Web Components specification. However, since v1 gained full support in 2020, the world of Web Components has seen even more changes. There are more plans for the future. Let’s look at some noteworthy examples built using the current standards and explore some new Web Components standards work that will be released in 2023 and beyond1.
Examples of Web Components Applications#
With all browsers supporting v1 Web Components, many companies have adopted and built significant businesses based on these new standards. Here are some examples that I think are worth noting.
YouTube#
YouTube is one of the earliest applications to adopt Web Components technology, using it to build its interface for years. Check the source code, and you will see various custom elements, from ytd-video-preview
to iron-ally-announcer
.
Photoshop#
Yes, Adobe has brought Photoshop to the browser using Lit. It is still in beta, and if you are an Adobe subscriber, you can try it out yourself. There are many custom elements throughout the application, from psw-app
, which forms the root of the application, to shell elements like psw-layers-panel
, and UI components like sp-action-button
.
MSN, Edge, Bing, VS Code, and More at Microsoft#
A few years ago, Microsoft restructured MSN using Web Components based on FAST. This improved performance by 30% to 50%, outperforming the previous version built with React.
The new Bing, based on OpenAI, is also built using FAST Web Components, as shown in the screenshot below, recently shared by one of the developers.
Even the Webview UI toolkit used to extend new features in VS Code is built using FAST Web Components.
In the past three years, around 1,500 teams/projects at Microsoft have adopted FAST Web Components.
Salesforce#
As one of the largest brands in the customer relationship management (CRM), sales, and marketing automation platform industry, Salesforce has been developing based on Lightning Web Components for years.
SpaceX#
Today, Web Components are even being used in space. SpaceX's crew display screens run Chromium and extensively use Web Components.
Current Standards#
Web standards are constantly evolving, including Web Components. In the three years since the v1 version was released to all major browsers, the number of features under Web Components has nearly doubled. Below is an illustration of various published, ongoing, and planned Web Components-related standards.
Let’s take a look at each of the six high-level categories in the illustration, categorized by functionality: Composition and Scope, Platform Interoperability, Rendering and Performance, Styling, Packaging and Distribution, API Paradigms.
Composition and Scope#
The scope/encapsulation features of Web Components are equally important for information hiding, maintenance, and codebase extensibility in traditional programming. However, when it comes to Web Components, they also provide additional metadata for HTML and CSS at runtime, which can be used to optimize rendering and layout.
Shadow DOM
Shadow DOM is the fundamental mechanism in HTML for scoping, encapsulating, and composing DOM and related styles. It is a multifaceted feature with many continuously expanding capabilities.
-
Named Slot Assignment (Fully Supported) — The original v1 Shadow DOM specification provides a fully declarative mechanism for using named
<slot>
elements in Shadow DOM to define placeholders for element composition. Developers simply place aslot
attribute on any child of the host element, and the browser will automatically "insert" the rendered output of that element into the slot's position. -
Open and Closed Modes (Fully Supported) — The
mode
option of the attachShadow() API in the v1 Shadow DOM specification is part of this. It allows component developers to choose their preferred encapsulation mode. Theopen
mode allows access to theshadowRoot
from outside the host element, while theclosed
mode prohibits access. -
Event Redirection (Fully Supported) — When events are triggered on elements inside the Shadow DOM, these events are "redirected" so that they appear to come from the host Shadow DOM. This capability of the v1 Shadow DOM specification is an important part of correctly encapsulating internal structures.
-
Manual Slot Assignment (Fully Supported) — The new assign API on the
slot
element extends the original slot assignment functionality of v1, providing an imperative API in addition to the previous declarative slot mechanism. -
Focus Delegation (Fully Supported) — This feature after v1 allows the Shadow DOM to inform the browser that when its host element gains focus, it should delegate focus to a specific element within the Shadow DOM. By default, the first focusable element is selected, but this behavior can be overridden using the
autofocus
attribute. -
Cross-root ARIA (Near Consensus) — The upcoming feature, which is nearing consensus among the community and browser vendors, will greatly simplify the association of ARIA key elements inside and outside the Shadow DOM. For example, associating a
label
element outside the Shadow DOM with aninput
element inside the Shadow DOM. There are already solutions for these types of ARIA scenarios today, but they are not easy to implement. Cross-root ARIA will greatly improve this situation. -
Using Custom Properties in Shadow CSS (Consensus) — Nowadays, some browsers can use @property syntax to customize CSS properties. However, this currently does not work in Shadow DOM. The CSS Object Model can always globally define these properties from custom element code, but providing this functionality declaratively in Shadow DOM is a commonsense improvement. This has reached consensus, so we hope to see this feature soon, as browsers more broadly support the new CSS syntax.
Scoped Element Registry (Consensus)
In the v1 specification for custom elements, all elements are registered in the global custom element registry through the customElements
global object. This new supplementary feature allows for the instantiation of non-global registries and the registration of custom elements within them.
const myRegistry = new CustomElementRegistry();
myRegistry.define("my-element", MyElement);
Elements in this registry are only defined for the Shadow DOM assigned to that registry. This greatly improves scoping in browsers, allowing elements to be defined for each shadow root as needed. When applied in browsers, this will be a significant advancement, opening the door to new architectural possibilities. Currently, there is consensus between the community and vendors, and Chromium is developing the first implementation.
Platform Interoperability#
One of the most important aspects of Web Components is how they achieve interoperability between components and platforms. Let’s look at some current and future features.
Custom Elements
-
Autonomous Custom Elements (Fully Supported) — This core feature of Web Components v1 defines custom elements that inherit from
HTMLElement
by registering a class with thecustomElements
global object here. Basic lifecycle callbacks and observing attributes are also part of the specification. -
Custom Built-in Elements (Rejected) — Initially, there was a proposal to allow inheritance from built-in elements (like
HTMLParagraphElement
), but WebKit implementers found several technical issues, so this specification has been rejected. It is likely to be removed in the future, so it should be avoided. See "Custom Attributes" below for potentially better alternatives.
Element Internals
A new API after v1, ElementInternals
, allows custom elements to integrate more deeply with existing DOM subsystems for platform-level integration.
-
Shadow Root Access (Fully Supported) — This simple feature addition allows component developers to retrieve a Shadow Root instance of a
closed
mode element. Without this feature, elements with declarative Shadow DOM inclosed
mode would not be able to access their root node at runtime. -
Custom Elements Associated with Forms (Fully Supported) — This important new feature allows custom elements to fully participate in forms, including form validation, submission, and reset.
-
Default Accessibility Roles, States, and Properties (Most Supported) — This new set of APIs allows for setting default accessibility features of custom elements by directly communicating with the platform internally, rather than through external attributes on the host element that may be inadvertently removed by users. Currently, all major browsers except Firefox support this new API, and for Firefox, a polyfill is provided. Given that Firefox has already implemented other parts of the
ElementInternals
API, I would be surprised if they do not release this feature in the near future.
Composed Selection (Consensus/No Specification)
This improvement proposes a new getComposedRange()
API for the Selection object, which allows the start and end of a range to span multiple Shadow Roots. It will also enhance browser consistency when handling these situations. There is broad consensus on this API draft, but a complete specification is still needed before browsers can implement it. You are unlikely to encounter this situation in normal Web Component development. It mainly involves the implementation of rich text editors.
Custom Attributes (Confirmed)
While this feature may not necessarily be part of Web Components, it overlaps significantly with the scenarios that Web Components aim to serve. This draft proposal enables the creation of reusable behaviors that can be attached to any HTML element, following a pattern similar to Web Components. For example, imagine if you wanted to apply a Material Design ripple effect to any HTML element; wouldn’t that be great?
<button material-ripple>Click Me</button>
In the draft proposal I prepared for TPAC 2022, I demonstrated what the programming model for this feature might look like:
class MaterialRipple extends Attr {
// ownerElement inherited from Attr
// name inherited from Attr
// value inherited from Attr
// ...
connectedCallback () {
// called when the ownerElement is connected to the DOM
// or when the attribute is added to an already connected owner
}
disconnectedCallback () {
// called when the ownerElement is disconnected from the DOM
// or when the attribute is removed from a connected owner
}
attributeChangedCallback() {
// called when the value property of this attribute changes
}
}
customAttributes.define("material-ripple", MaterialRipple);
You will notice that this pattern and lifecycle are consistent with Web Components. This will also provide a better and more robust alternative to the is
attribute in the rejected custom built-in elements proposal.
Rendering and Performance#
Rendering and performance are critical for Web Components. While the basic functionality is in place, this remains an active area of exploration, discussion, and future innovation.
HTML Template Element (Fully Supported)
The HTMLTemplateElement
and its ability to define lazy HTML content are key parts of v1 Web Components functionality. Before this element was introduced, there was no way to declare HTML that would not be activated by the browser, making it difficult to create components that needed to repeatedly render the same HTML on demand.
Declarative Shadow DOM (Most Supported)
The v1 specification of Shadow DOM only allowed the creation of Shadow Roots through the attachShadow()
JavaScript API. This new enhancement of Shadow DOM allows for fully declaring Shadow DOM content in HTML without using JavaScript, providing interesting possibilities for server frameworks.
<host-element>
<template shadowrootmode="open">
<slot></slot>
</template>
<h2>Light content</h2>>
</host-element>
This specification reuses the template
element. Don’t get confused by this. It is not a template; it is the active DOM flowing into the Shadow Root by the HTML parser.
Currently, all browsers except Firefox support declarative Shadow DOM. If needed, this feature can be polyfilled with a few lines of JavaScript.
Child Node Change Callback (Proposed)
Web Components have a clearly defined lifecycle in the v1 specification for custom elements, but that does not mean we cannot extend this lifecycle in the future. One common challenge for developers is enabling Web Components to respond to the addition or removal of child nodes. While this can currently be achieved using the slotchange event and MutationObserver, it would be better if there were a lifecycle callback function like childrenChangedCallback()
that could provide better performance, simplification, and integration with the HTML parser itself. There is currently a draft proposal, and implementers have shown interest. A complete proposal is needed to push this feature into the next stage.
Template Instantiation
While HTML has templates, it does not yet have a mechanism to instantiate templates connected to data and update them when their related data changes. The area of "template instantiation" has several independently valuable parts.
- DOM Parts (Proposed) - This proposal will provide a standard mechanism to insert or replace content at specific locations in the DOM tree. You can think of it as a low-level enabler that helps create more efficient template engines and batch updates to existing Web Component libraries and JavaScript frameworks. It does not provide a responsive solution or template syntax; it only provides low-level standard infrastructure for locating and updating DOM parts.
- Template Syntax (Confirmed) - Once the low-level infrastructure for locating and batch updating is in place and successfully used by existing libraries, the big debate about syntax will begin. Template syntax is a very contentious issue, but we recognize that HTML should have a basic language to handle this, even if it is just to provide a compilation target for other libraries.
- Responsiveness (Confirmed) - DOM parts provide a standard mechanism for batch updating the DOM. Template syntax provides a declarative mechanism for creating DOM parts. What remains is to determine when DOM part updates should be executed. This is where responsiveness comes in to complete the picture. This is another contentious issue, but there are some precedents, such as the
attributeChangedCallback()
of Web Components. This topic needs more exploration.
The work category for template instantiation is broken down into the three sub-features mentioned above, aiming to first address some of the less contentious issues and provide a path for existing libraries and frameworks to leverage less subjective, performance-improving features, avoiding excessive controversy in the community.
Styling#
While Shadow DOM provides encapsulation for styles, many CSS features are directly related to Web Components and are very important in everyday use.
Usage
Several current and future standards relate to how Web Components use styles to create the presentation of Shadow DOM. While it has always been possible to create style elements in Shadow DOM, new standards offer better readability and performance advantages.
- Constructable Stylesheets (Fully Supported) — Did you know that before this standard, it was actually impossible to create
CSSStyleSheet
instances? This standard fixed that issue, and now you can write code likenew CSSStyleSheet()
. This capability makes it possible to create and use styles more dynamically in Web Components, including sharing stylesheets between components. - Adopted Stylesheets (Fully Supported) — For a given
CSSStyleSheet
instance, how can it be associated with a specific Shadow Root or the global document? This new standard adds anadoptedStyleSheets
array to thedocument
and all Shadow Root instances. Simply pushing a stylesheet into that array allows it to be used. - CSS Module Scripts (Chromium) — Constructable stylesheets and adopted stylesheets themselves provide the raw mechanism for creating, sharing, and associating document stylesheets, but still require writing CSS code in JavaScript. The CSS Module Scripts standard allows importing
.css
files using JavaScript modules, automatically creating aCSSStyleSheet
instance without having to switch back and forth between CSS runtime and JavaScript runtime. - Declarative CSS Modules (Confirmed) — With the advent of declarative Shadow DOM and adopted stylesheets, several temporary proposals have been created to declare CSS modules and associate them with declarative Shadow DOM. More exploration is needed in this area, but it is an exciting possibility for the future of HTML and CSS.
Rendering
Primarily, CSS focuses on rendering issues. There are some standards that extend the styling capabilities of Web Components.
Not just for Web Components, custom CSS properties are a very important specification for creating component systems, allowing for the creation of local CSS variables that can be used within shadow roots.
- CSS Shadow Parts (Fully Supported) — CSS parts allow elements in Shadow DOM to be declared as "parts" that can be styled using external selectors. This is achieved through the
part
attribute and the exportparts attribute for nested scenarios. - CSS Custom States (Chromium) — Native elements can have custom states available in CSS selectors. For example, the "checked" and "unchecked" states of checkboxes. This new feature allows Web Components to define their own states. There is consensus on this, and Chromium has released the first implementation, which can be accessed via
ElementInternals
. While waiting for other browsers to follow suit, polyfills can be used for support. - CSS Theming (Proposed) — Although rich theming can be achieved through careful use of CSS custom properties and CSS Shadow Parts, the process can be simplified and improved by explicitly introducing the concept of theming into CSS.
- Open Shadow Root Styles (Confirmed) — While it is possible to share any global CSS in Shadow Root using constructable stylesheets and adopted stylesheets, this may not be an intuitive process for regular web developers. There are some exploratory mechanisms that explicitly allow external CSS to enter certain shadow roots.
Packaging and Distribution#
So far, we have mainly discussed standards related to the implementation of Web Components. But it is equally important to consider how components are packaged and loaded.
Lazy Loading of Custom Elements (Proposed)
Now that we can define components using the global customElements
registry, we will soon be able to use custom registries. However, in both cases, the implementation of the component must be loaded before the component is defined. With lazy loading of custom elements, developers will be able to inform the platform about the element but can delay loading it until the element first appears in the document. It might work like this:
customElements.defineLazy(
"my-element",
async () => (await import("my-element.js")).default
);
This specification seems to be regarded as a good thing by most, especially for certain architectures. However, the details of the proposal are still under debate.
HTML Module Scripts (Confirmed)
HTML module scripts are the HTML equivalent of CSS module scripts. Through the HTML Module Scripts proposal, templates (and other HTML fragments) will be directly importable through the JS module system. Currently, there is only a draft proposal, and many details still need further discussion, but this is considered an important long-term enhancement, especially considering the potential for Web Components that consist of only a single HTML file in the future.
API Paradigms#
The last category of standards is somewhat different from everything I discussed earlier. These standards involve the fundamental programming paradigms of Web Components. Web Components v1 is primarily an imperative JavaScript programming model. There are some notable exceptions, such as declarative slot assignment. But fundamentally, it is entirely imperative. Since v1, we have been working to introduce more and more declarative features. One good example is declarative Shadow DOM. Overall, it is best to provide both declarative and imperative APIs for all scenarios. But the ultimate goal is to have some fully declarative definition of Web Components so that servers can send element definitions to browsers, working completely in a noscript context. We still have a way to go, but when we get there, it will fundamentally change client and server development.
What’s Next#
The work on standards is always ongoing. In fact, starting today, the W3C Web Components Community Group is holding its Spring 2023 face-to-face event. Like TPAC, this is an opportunity for library authors, component creators, browser vendors, and others to come together and spend dedicated time addressing the details of specifications that still need consensus or have open issues. I look forward to updating everyone on the outcomes of the event in future blog posts. Please follow/subscribe to ensure you receive updates 😄
Summary#
I hope this journey through the Web Components standards has been meaningful for you. It’s exciting to see how far we’ve come and what awaits us in the future. With the release of v1, the features published over the past few years have doubled, and with exciting new features on the horizon, now is a great time to be a web developer.