• Success Criterion 4.1.2
  • Conformance level A

Web Component Whose Shadow DOM Hides All Its Semantics

4.1.2 — Name, Role, Value

Scenario

Setting

A hospital's patient portal appointment scheduler

What’s wrong

Web components with closed shadow DOM (hidden internal code) leaking no semantics (no ElementInternals/ARIA reflected).

Example

class ApptSlotPicker extends HTMLElement {
  constructor() {
    super();
    this.attachShadow({ mode: 'closed' });
    this.shadowRoot.innerHTML = `<div class="slot">9:00 AM</div>`;
  }
}
customElements.define('appt-slot-picker', ApptSlotPicker);
<!-- the closed shadow root hides the clickable slot divs from assistive tech,
     and no role or name is reflected onto the host element -->

Why it matters

A patient using a screen reader gets an empty custom element announced, since closed shadow DOM blocks access to the slot content.

How to test

Inspect a web component's shadow DOM in DevTools' Accessibility panel: if no semantics (ElementInternals or reflected ARIA) are exposed from inside the shadow root, it fails.

How to fix

Use an open shadow root plus ElementInternals to reflect role and state onto the host, or avoid closed mode here.

class ApptSlotPicker extends HTMLElement {
  constructor() {
    super();
    this.internals = this.attachInternals();
    this.internals.role = 'listbox';
    this.attachShadow({ mode: 'open' });
    this.shadowRoot.innerHTML = `<div role="option" tabindex="0">9:00 AM</div>`;
  }
}

Outcome

A patient hears each appointment slot announced and books the 9 AM opening.

Who is affected

Screen reader users booking an appointment cannot perceive or select any of the available time slots.

Learn more