Copyright © 2024 the Contributors to the Web Components Community Group: 2021 Spec/API status Specification, published by the Web Components Community Group under the W3C Community Contributor License Agreement (CLA). A human-readable summary is available.
This is required.
This specification was published by the Web Components Community Group. It is not a W3C Standard nor is it on the W3C Standards Track. Please note that under the W3C Community Contributor License Agreement (CLA) there is a limited opt-out and other conditions apply. Learn more about W3C Community and Business Groups.
This is required.
GitHub Issues are preferred for discussion of this specification.
This section is non-normative.
The initial slate of APIs that browsers shipped with web components "v1" left many important features and use-cases on a future to-do list, to be finalized out after the core custom element and shadow DOM features landed. While the web components GitHub issues and face-to-face meets have tracked and discussed many of these features individually, there hasn't been a comprehensive overview of what's left to "finish" web components.
This document tries to highlight the main features that are lacking from the web components spec that either block adoption for more developers and frameworks, or cause pain points for existing developers.
It's worth noting that many of these pain points are directly related to Shadow DOM's encapsulation. While there are many benefits to some types of widely shared components to strong encapsulation, the friction of strong encapsulation has prevented most developers from adopting Shadow DOM, to the point of there being alternate proposals for style scoping that don't use Shadow DOM. We urge browser vendors to recognize these barriers and work to make Shadow DOM more usable by more developers.
Feature or Problem | GitHub Issue(s) | Priority | Status(?) |
---|---|---|---|
Form-Associated Custom Elements | WICG/webcomponents#187 | Critical | Some implementation |
Cross-root ARIA |
WICG/aom#169 WICG/aom#107 WICG/webcomponents#917 WICG/webcomponents#916 |
Critical | Uncertain |
Constructable Stylesheets & adoptedStyleSheets | WICG/webcomponents#468 | Critical | Some implementation |
CSS Module Scripts | WICG/webcomponents#759 | Critical | Some implementation |
Scoped Element Registries | WICG/webcomponents#716 | Critical | Consensus |
Declarative Shadow DOM | whatwg/dom#831 | Critical | Partial consensus, some implementation |
Composed Selection | WICG/webcomponents#79 | High | Partial consensus, divergent partial implementations |
Declarative CSS Modules | WICG/webcomponents#939 | High | Not Addressed |
Children changed callback | WICG/webcomponents#809 | High | --- |
Open styling of shadow roots | WICG/webcomponents#909 | High | Not addressed |
Declarative custom elements | Strawperson | High | Not addressed |
--- | --- | --- | --- |
Form-associated custom elements allow custom elements to participate in forms to the same degree as native elements, including integrations with the form’s validation, state, and submission as well as exposing the Accessibility Object Model to the element.
A sample use case can be found in this article by Caleb Williams.
One of the most common use cases for web components is creating form controls not available natively. Some examples include switches and credit card inputs.
There is no way for forms to fully integrate with form elements located in a different shadow root the same way they would with form elements in the same root. The only options available to achieve a similar result are:
This situation has forced developers to either not use web components for form elements or create their own form systems that allow for full integration (e.g. many big web component libraries such as Lion or Shoelace provide form systems that integrate with their components). This limits the reach web components could have as plug-in form elements for projects created with different tech stacks.
It's critically important that content on the web be accessible. Making web component content accessible currently requires many complicated and only partially-successful workarounds, such as:
Constructable Stylesheets and adoptedStyleSheets
enable adding styles directly to shadow roots without creating new DOM elements. Because a single stylesheet object can be adopted by multiple scopes, it also allows sharing of styles that can be centrally modified.
<style>
elements for each style used in each shadow root has a measurable performance overhead.CSS Module Scripts allow JavaScript modules to import style sheets. They can then be applied to a document or shadow root using adoptedStyleSheets in the same way as constructible style sheets.
import styleSheet from "./styles.css" assert { type: "css" };
document.adoptedStyleSheets = [ styleSheet ];
<style>
or <link>
elements that need to be created in each element instance.For further motivational details, see this explainer document: webcomponents/css-modules-v1-explainer.md at gh-pages · WICG/webcomponents.
Scoped element registries allow custom element definitions to be scoped to one or more shadow roots. This allows the same tag name to be used with different implementations in different parts of the page, greatly reducing tag name collisions.
There are a number of situations where multiple definitions of an element may be loaded into a page, leading to errors when the second definition executes:
<my-button>
.A partial polyfill for scoped custom element registries is available, but it has a number of drawbacks, including lower performance, and a requirement that all definitions have the same set of observed attributes.
Declarative Shadow DOM is a mechanism to express Shadow DOM using only HTML, with no dependency on JavaScript, much like light DOM can be declaratively expressed today.
For details, see this article by Jason Miller and Mason Freed.
Without Declarative Shadow DOM, web components depend on rendering environments that support JavaScript. This limits their use in:
Chrome has experimental support and a polyfill for Declarative Shadow DOM, but complete workarounds are not possible since Declarative Shadow DOM is a browser-level feature. Frameworks and libraries have hacked around this issue by prerendering sites, pages, or components in JavaScript-supporting environments prior to delivering HTML.
The ability to get a Selection from shadowRoot.getSelection()
or document.getSelection()
, then subsequently identify the selection range across composed trees of light and/or shadow DOM.
TPAC 18 resolved in consensus to add getComposedRange()
to the existing Selection object (explainer). However, Selection.getComposedRange()
is not yet implemented in any browser. Browsers also diverge in their implementations of shadowRoot.getSelection
:
isCollapsed
to true.shadowRoot.getSelection
, but returns shadow root anchorNodes from document.getSelection
. This bug can be leveraged to polyfill shadowRoot.getSelection
.shadowRoot.getSelection
and cannot be polyfilled.Selection does not work consistently, or at all, across or within shadow roots. This makes fully-featured rich-text editors impossible to implement via web components. Some of the web’s most popular editors have issues that are blocked on this functionality:
Declarative shadow roots and constructible stylesheets need to be made to work together so that stylesheets added to shadow roots can be round-tripped through HTML serialization and deserialization.
Currently, there is no way to associate a declarative shadow root with a constructed stylesheet. This means that when a custom element with a shadow root and adopted stylesheets is serialized to HTML, it either loses its styling or some additional code has to convert the adopted stylesheets to style tags and insert them into the markup.
This is a proposal to add a new callback to the CEReaction extended attribute that would fire once an element's child has changed. This new callback would allow developers to deterministically know when child elements are added or removed, taking into account slotting.
Open-styleable shadow roots would be a new mode on shadow roots that allow selectors from the shadow root's containing scope. This will allow component's internal DOM to be styled by page styles if there is a chain of open-styleable shadow roots up to the document scope - which in turn allow those components to be made to be compatible with existing pages so that projects can incrementally adopt shadow DOM.
Many potential consumers and providers of web components have raised the issue that they need to make components styleable with existing, and potentially unknown stylesheets. This is a common occurrence with systems like Bootstrap, Tailwind, or corporate stylesheets. The stylesheet may be loaded at the page level and maintained and distributed by a different team than the team building components. This scenario is extremely common for projects that are trying to port existing components to web components.
A common request for a solution to this problem is to be able to opt shadow roots into including styles from the scope above them. A chain of these "open-styleable" shadow roots from the top-level down would allow page styles to select against nodes in the shadow root.
While this does loosen encapsulation a lot, it also preserves many of the benefits of shadow DOM including upper bound style encapsulation, lower bound encapsulation to non-open-styleable shadow roots, DOM composition with slotting, and providing a scope for custom element registrations, ARIA/focus delegation, event composition, attaching constructible stylesheets and more.
We estimate this is a extremely large blocker to shadow DOM adoption. The inability to style shadow roots is one of the most common complaints on various GitHub/Twitter/Chat comments.
There is theoretically a workaround where a component reads styles from its containing scope and copies them into its own shadow root. This is difficult to make reactive to changes in DOM structure and new styles being added in parent scopes, and requires script so doesn't work with declarative shadow DOM.
ְDevelopers would like to define a custom element, it’s shadow-root, and styles from HTML, without need for JavaScript.
This would allow them to share reusable components easily without need for extra tooling, and to load them in <noscript>
contexts. Declarative Shadow DOM allows developers to emulate this using build-tools, but requires repeating the declared shadow roots for each instance.
---
---
As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.
This is required for specifications that contain normative material.