Web Components Community Group: 2023 Spec/API status

Draft Community Group Report

Latest published version:
none
Editors:
Westbrook Johnson
Elliott Marquez
Michael Warren
Feedback:
GitHub w3c/webcomponents-cg (pull requests, new issue, open issues)

Abstract

The following aims to support implementors in prioritizing, finalizing, and shipping new and agreed upon specifications in accordance with what is most needed by the web component developing community.

Status of This Document

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.

The 2023 report is currently being drafted.

GitHub Issues are preferred for discussion of this specification.

1. Introduction

This section is non-normative.

Web component features in the platform swing broadly from twinkle in someone's eye to just waiting for that last browser vendor to ship in the wild. Along that spectrum, there are a myriad of features that browser implementors and web developers could focus on and it's difficult to always align on which are most important. We, the Web Components Community Group, look to build on our work from 2021 and 2022 and continue to shed light on the priorities in this space as seen by developers conuming these features.

Taking the feedback from previous years to heart, we are drew out four features of the highest priority. Each are at different places on the spectrum of "ready to consume", and we look forward to working more closely with vendors in making progress towards that goal. The four features are listed below by status:

1.1 Seeking Browser Parity

We noticed the following specs already have a high degree of alignment from an implementation perspective, but support in browsers is still not equally distributed. Filling in these gaps would be a big win for users and developers alike for a more predictable web.

1.2 Seeking Initial Prototyping

The following specs have recieved a quality review at the proposal stage and are ready to be prototyped in browser. What sort of support could the Web Components Community Group lend to browser implementors as part of this process?

1.3 Seeking specification concensus

The following specs we see as highly valuable to the developer community for being able to deliver great web experiences to users when using Web Components. As it pertains to topics like Aria and SSR, these specs just need a little more alignment across browser implementors so that consensus can be achieved.

1.4 Table of Contents

Feature or Problem GitHub Issue(s) Status(?)
Cross-root ARIA WICG/aom#169
WICG/aom#107
WICG/webcomponents#917
WICG/webcomponents#916
Uncertain
Declarative Shadow DOM whatwg/dom#831 Concensus, lacking parity in implementation
Scoped Element Registries WICG/webcomponents#716 Consensus, lacking initial prototype
CSS Slot Content Detection w3c/csswg-drafts#7922 WICG/webcomponents#936 w3c/csswg-drafts#6867 Uncertain

2. Cross-root ARIA

2.2 Description

This problem space is expertly described by Alice Boxhall in this blog post.

In short, accessibility with shadow roots in broken when addressed via the patterns that web developers have come to be acustomed to in their work.

2.3 Status

Implementors participating in bi-weekly Accessibility Object Model meetings with at the WICG have implied

2.4 Key Scenarios

This plays out in a Combobox pattern as follows:


  <x-label id="x-label">
    #shadowRoot
    | <label for="">Example Label</label>
  </x-label>
  <x-combobox id="x-combobox-1">
    #shadowRoot
    | <x-input>
    |   #shadowRoot
    |   | <input
    |   |   role="combobox"
    |   |   aria-expanded="true"
    |   | />
    | </x-input>
    | <button aria-label="Open" aria-expanded="true">v</button>
    |
    | <x-listbox id="x-listbox-1">
    |   #shadowRoot
    |   | <div role="listbox">
    |   |   <div role="option">Option 1</div>
    |   |   <div role="option">Option 2</div>
    |   |   <div role="option">Option 3</div>
    |   | </div>
    | </x-listbox>
  </x-combobox>

Even when leveraging the available aria attributes in this case there is no way to assocaite the x-label to the x-input or either of the [role="listbox"] or [role="option"] elements to it either.

Less complex patterns are similarly blocked by current APIs. Here we see a custom radio group:


  <div role="radiogroup">
    <x-button>
      #shadowRoot
      | <button role="radio"></button>
    </x-button>
    <x-button>
      #shadowRoot
      | <button role="radio"></button>
    </x-button>
    <x-button>
      #shadowRoot
      | <button role="radio"></button>
    </x-button>
  </div>

Due to the shadow boundary and DOM element between the [role="radio"] element and the [role="radiogroup"] ancestor, there is no way to complete the accessibility tree that is needed to provide information about this interface to screen readers.

2.5 Initial API Summary/Quick API Proposal

Leveraging the Element Handles API the Combobox pattern would be work out as follows:


  <x-label id="x-label" importhandles="label-for: x-combobox-1::handle(the-input)">
    #shadowRoot
    | <label for=":host::handle(label-for)">Example Label</label>
  </x-label>
  <x-combobox id="x-combobox-1">
    #shadowRoot
    | <x-input 
    |   exporthandles="the-input"
    |   importhandles="my-activedescendant: x-listbox-1::handle(active), my-listbox: x-listbox-1::handle(the-listbox)">
    |   #shadowRoot
    |   | <input
    |   |   role="combobox"
    |   |   handle="the-input"
    |   |   aria-controls=":host::handle(my-listbox)"
    |   |   aria-activedescendant=":host::handle(my-activedescendant)"
    |   |   aria-expanded="true"
    |   | />
    | </x-input>
    | <button aria-label="Open" aria-expanded="true">v</button>
    |
    | <x-listbox id="x-listbox-1">
    |   #shadowRoot
    |   | <div role="listbox" handle="the-listbox">
    |   |   <div role="option" handle="opt1 active">Option 1</div>
    |   |   <div role="option" handle="opt2">Option 2</div>
    |   |   <div role="option" handle="opt3">Option 3</div>
    |   | </div>
    | </x-listbox>
  </x-combobox>

Leveraging the Aria Delegate API the radio group pattern could be acheived via:


  <div role="radiogroup">
    <x-button role="radio">
      #shadowRoot shadowrootsemanticdelegate="button"
      | <button id="button"></button>
    </x-button>
    <x-button role="radio">
      #shadowRoot shadowrootsemanticdelegate="button"
      | <button role="radio" id="button"></button>
    </x-button>
    <x-button>
      #shadowRoot shadowrootsemanticdelegate="button"
      | <button id="button"></button>
    </x-button>
  </div>

2.7 Open Questions

3. CSS Slot Content Detection

3.2 Description

In shadow DOM, projection is the concept of placing an element into the light DOM and rendering it in a custom position via slots in the shadow DOM. This allows for greater control over the layout and styling of elements while also giving the user direct control over the contents and styling since the nodes are in the light DOM.

These are the current mechanisms in which to interact with slotted content:

3.3 Status

3.4 Initial API Summary/Quick API Proposal

Summary or proposal based on current status; paragraph(s) and code.

3.5 Key Scenarios

Currently there is no CSS-only way to determine whether a <slot> has content assigned to it without requiring the consumer of a web component to explicitly state so.

3.5.1 Use Case Example

In the web component-based https://github.com/material-components/material-web, there is the Dialog component. The dialog component can have three sections slotted in:

  • slot=headline
  • slot=content
  • slot=actions

When the dialog’s content is slotted, the dialog must show a divider which is rendered in its shadow DOM. In essence the <md-divider> which is a sibling to <slot name=”content”> must be styled. e.g


  <md-dialog has-content>
    <template shadowrootmode="open">
      <style>
        md-divider {
          display: none;
        }
        :host([has-content]) md-divider {
          display: flex;
        }
      </style>
      ...
      <div class="content">
        <md-divider class="before"></md-divider>
        <slot name="content"></slot>
        <md-divider class="after"></md-divider>
      </div>
      ...
    </template>
  
    <div slot="content">
      Really long content ...
    </div>
  </md-dialog>

The DX would be cleaner if has-content could be inferred by the CSS rather than the user having to apply it or JS having to run at runtime.

Using /slotted/ for the sake of example.


  <md-dialog>
    <template shadowrootmode="open">
      <style>
        md-divider {
          display: none;
        }
        .content md-divider:has(~ slot/slotted/ *),
        .content slot:has(/slotted/ *) ~ md-divider {
          display: flex;
        }
      </style>
      ...
      <div class="content">
        <md-divider class="before"></md-divider>
        <slot name="content"></slot>
        <md-divider class="after"></md-divider>
      </div>
      ...
    </template>
  
    <div slot="content">
      Really long content ...
    </div>
  </md-dialog>

This removes the need for the user to declare that there is slotted content twice:

  • div[slot=content]
  • md-dialog[has-content]

3.6 Concerns

3.7 Dissenting Opinion

3.9 Open Questions

4. Declarative Shadow DOM

4.2 Description

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.

4.3 Status

4.4 Initial API Summary/Quick API Proposal

Below is an example taken from the web.dev blog on Declarative Shadow DOM.

<host-element>
  <template shadowroot="open">
    <slot></slot>
  </template>
  <h2>Light content</h2>>
</host-element>

4.5 Key Scenarios

Server-Side Rendering: Without Declarative Shadow DOM, servers cannot deliver complete websites that include web component content. Markup cannot be efficiently delivered and then hydrated with JavaScript client-side.

JavaScript-less environments: Many web components could be implemented without JavaScript, taking advantage of encapsulated DOM and styles. However, web components cannot currently be rendered by users who have JavaScript disabled. Developers who are more comfortable with markup than with scripting may avoid shadow DOM altogether due to its tight coupling with JavaScript..

4.6 Concerns

4.7 Dissenting Opinion

4.9 Open Questions

5. Scoped Element Registries

5.2 Description

When building a custom element, the current API is the customElements.define(tagName, klass) which takes a custom tag name and a JS class reference and globally registers a new custom element.

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.

5.3 Status

5.4 Initial API Summary/Quick API Proposal

5.5 Key Scenarios

The issue with the current custom element definition approach is that there is only a single registry in the global space. Having a single global registry means also having the possibility of tag name or class collisions which will present problems when different released versions of the same custom element need to exist on a single HTML page at the same time.

5.5.1 Design system use case

Design system teams are largely responsible for making standalone reusable components that can be consumed in all manner of applications across an organization. Design system components can be small and directed (something like x-label or coarse-grained like x-accordion). For DRY principles, it is often very desirable for large coarse-grained components to internally (in the shadow root render template) use smaller components to keep logic encapsulated.

When a design system component internally uses a component that a consuming application also uses, a version conflict can arise. If the large component uses x-small-component version 1.0.0, and the application uses x-small-component version 2.0.0, the custom element tag names will be the same, and both versions will attempt to register in the global registry.

The first element registered will "win". The second registration will fail. Whichever element "wins" will cause functional failures for either the application or design system component, depending on which component registration "wins".

5.5.2 Micro-front end use case

Micro-front-end architecture (MFE) is rising in popularity as a way to develop smaller pieces of what will be the final user-facing application, then assemble those pieces at runtime in some sort of shell application, service worker, etc. The micro-front-end architecture basically means that whole pieces of applications will be developed independently by separate probably-siloed teams then placed on the same page at runtime.

When MFE remote component 1 uses a certain version of a component, and MFE remote component 2 uses a different version of that same component, and both attempt to register in the same global registry under the same tag name, version conflicts arise.

If MFE 1 uses x-component version 1.0.0, and MFE 2 uses x-component 2.0.0, whichever component registration comes first "wins" and breaks the other MFE remote component. If 1.0.0 wins, then MFE 2 is broken because it is expecting 2.0.0 and use the 2.0.0 component API. Likewise, if 2.0.0 wins, MFE 1 breaks because it is dependent on the 1.0.0 component API which may not be supported in 2.0.0.

5.6 Polyfills

5.6.1 Mixin

The mixins below are offered as helper libraries to consume the polyfill implementation in an consistent, automated way.

5.7 Concerns

5.8 Dissenting Opinion

5.10 Open Questions

6. Conformance

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.

A. Index

A.1 Terms defined by this specification

A.2 Terms defined by reference