CONTRIBUTOR-DOCS / Project planning / Components / Popover / Popover accessibility migration analysis
In this doc
This document sets accessibility expectations for 2nd-gen Popover in Spectrum Web Components: shared popover styles (visual layer only) and a positioning host (swc-popover, name TBD) for anchor-relative placement. swc-popover is a container for listbox, menu, tooltip, and similar content—not a replacement for those patterns. ARIA roles, states, and properties, focus management, and keyboard navigation are implemented by the components that use swc-popover (for example action menu, combobox, tooltip), not by the popover host. Modal dialogs use shared popover styles on the dialog surface when the design needs that chrome; they do not use the <swc-popover> component (that host is for anchor-positioned UI only: menus, combobox popups, tooltips, and similar). The target is WCAG 2.2 Level AA. Product alignment: React Spectrum Popover.
Popover migration roadmap for the 1st-gen / 2nd-gen split (styles vs positioning), deprecation, and consumer migration (SWC-2003).
- Popover styles are a shared Spectrum visual layer (for example border, drop shadow, tip). They do not set ARIA or keyboard behavior.
swc-popoveris a positioning container: it applies those styles and anchored placement (for example CSS anchor positioning and/or Floating UI) around slotted content. It is not a menu, listbox, or tooltip by itself—those are the components or markup patterns you host inside it.- Consumers of
swc-popover(action menu, combobox, tooltip, and similar) own ARIA roles, states, and properties, plus focus management and keyboard navigation for their pattern; the popover host does not implement those.
- Modal dialog (focus trap,
role="dialog",aria-modal) — use the APG dialog (modal) pattern on the appropriate nodes and any overlay or focus orchestration your stack provides. Do not use<swc-popover>for modals (no anchor-to-trigger placement). You may apply shared popover styles to the dialog surface when the design calls for that look. - Menu or combobox popups — APG menubutton or APG combobox; the popover is only a positioned box you style with popover styles or place inside
swc-popover.
- Not a menu, listbox, tooltip, or other APG widget in one tag—
swc-popoveris only a container and positioning shell; the components or author markup inside provide semantics and interaction. - Not a full “accessible overlay in one import”: inert backdrops, open state, and focus orchestration are separate (app or higher-level primitives) unless a future doc specifies otherwise.
- Not a wholesale drop-in for every 1st-gen overlay use. Tooltips are expected to adopt
swc-popover-style anchoring instead of overlay-driven tooltip placement. Action menu (dropdown) and combobox (listbox popup) are plannedswc-popoverhost call sites. Modals and dialogs use shared popover styles on the dialog surface, not theswc-popoverhost (see roadmap — Planned consumers and Overview).
- 1st-gen
sp-popoveris primarily styling. Many call sites (for example Picker) setrole="presentation"on the host and place ARIA on child content. - 2nd-gen (planned, roadmap — Planned consumers): action menu (dropdown), combobox (listbox), tooltip (replacing overlay-based positioning for that pattern). Modal / dialog: shared popover styles on the surface, not the
swc-popoverhost (see roadmap — Overview).
- The APG “read me first” model does not define a “popover” widget. Overlay surfaces are exposed to assistive technology through dialog, listbox / menu / grid popup, and other patterns plus their controlling widgets (for example combobox).
- Name, role, and value (WCAG 4.1.2) for the interactive experience come from slotted content and the trigger pattern, not from the unlabeled shell. See Semantic HTML and ARIA (2nd-gen guide).
| Idea | Plain meaning |
|---|---|
| Non-text contrast (1.4.11) | Shared popover chrome (border, tip, drop shadow) should be distinguishable on typical backgrounds. Do not reintroduce 1st-gen placement issues such as SWC-917 (RTL tip) in 2nd-gen. |
| Focus order (2.4.3) and focus visible (2.4.7) | The swc-popover host does not define tab order. Modals and dialogs (popover styles on the surface, no swc-popover host) and combobox / menu (with swc-popover) each follow their own focus pattern. |
| Name, role, value (4.1.2) | Belongs in focusable, labeled content (listbox, menu, dialog body), not unlabeled chrome—whether that is the swc-popover host or a modal surface that only uses shared popover styles. |
| Animation from interactions (2.3.3) (if open or placement transitions) | If the layer adds entry/exit motion, respect prefers-reduced-motion (or equivalent). |
Bottom line: Shared popover styles and the swc-popover host cover presentation and anchor placement for anchored UIs. Modals and dialogs use popover styles on the dialog surface but not the swc-popover host—they are not positioned relative to a trigger like a menu or tooltip. Accessibility comes from the pattern and content; use Keyboard testing (2nd-gen guide) for the pattern you ship.
| Jira | Type | Status (snapshot) | Resolution (snapshot) | Summary |
|---|---|---|---|---|
| SWC-933 / SWC-932 | Bug | Blocked / To Do | Unresolved | Picker: arrow navigation in list when popover is the overlay |
| SWC-917 | Bug | To Do | Unresolved | Popover: tip placement in RTL |
| SWC-1227 | Story | To Do | Unresolved | docs: migration documentation (Popover, Picker, Combobox, Coach mark, etc.) |
| SWC-1994 | Story | To Do | Unresolved | A11y(popover): recommendations for 2nd-gen migration |
Component tag may change until API freeze; this section describes the positioning + styles host, not 1st-gen sp-popover alone. swc-popover is a container, not a replacement for menu, listbox, or tooltip as full widgets—it wraps the surface those components render into. ARIA, focus, and keyboard are implemented by the consumer components that use this host (action menu, combobox, tooltip, and similar).
| Topic | What to do |
|---|---|
| Consumer owns semantics and behavior | Parent or consumer components (action menu, combobox, tooltip, and similar) set and maintain ARIA roles, states, and behaviors for their pattern on content inside or coordinated with swc-popover. The swc-popover host does not implement those patterns for you—it is not a substitute for a menu, listbox, or tooltip component. |
| No default ARIA on host | Do not set a default role or aria-* on swc-popover in the unstyled geometry story. Shared popover CSS also must not set ARIA. Align with the spirit of React Spectrum Popover props (positioning, visual props), not a dialog in one tag. If a build ever exposes a host role for a special case, that must be a separate, documented API. |
| Not a “semantic widget” host | The host is not dialog or menu by default. If another role is required, that belongs in child markup (the dialog surface, the listbox container) or a different primitive, not a role override that pretends the box is a menu or dialog. |
| Labels and ids | aria-labelledby, aria-describedby, and id wiring for a dialog or combobox listbox live in the same document root as the labeled nodes (light DOM in typical Lit usage). Avoid aria-* that must resolve across disconnected shadow roots for the default swc-popover design. |
| 1st-gen pattern | Call sites that used sp-popover with role="presentation" and ARIA on children (for example Picker) are the reference for chrome vs content; 2nd-gen continues separating anchored chrome from pattern ARIA. |
None: target is a host that does not require aria-labelledby / aria-describedby targets to live in a different shadow root than the labelled content. If a small shadow exists for a tip, keep labels and ARIA in the light tree for composed patterns. Shared style-only CSS has no ID-ref concerns.
- Default
swc-popoverhost: no exposed role or accessible name; the meaning is in slotted or projected children and the controlling trigger. - When children implement a pattern (for example a listbox, role
dialogon an inner node), the tree for that pattern follows the APG for that content; the outer host remains a neutral shell unless a separate API explicitly adds a role.
Does not apply. swc-popover is not a form-associated custom element and is not a labeled control. Slotted form fields use normal <label>, aria-labelledby, and pattern-specific wiring documented on those controls—not host-level label association on the popover.
Does not apply to the swc-popover host or to shared popover style modules. The host does not establish aria-live regions, role="status" or role="alert", or loading/announcement behavior. That belongs to slotted content and parent patterns (for example combobox or dialog). If a child uses a live region, follow that widget’s a11y doc; avoid aria-live="assertive" for routine progress, and use polite sparingly when many regions could update together and create noisy screen reader output.
Optional skill subsection ### Assistive technology, live regions is not added separately: the same product answer is no default live-region behavior on the host, as stated in this Live regions block.
Intentionally omitted. This doc does not add a separate ### Motion block under Recommendations. WCAG 2.3.3 and reduced-motion expectations for any open or placement transitions are only covered in Guidelines that apply, consistent with the accessibility-migration-analysis practice of keeping motion in the Guidelines table for components that are not progress-like (compare Progress circle, which also centralizes motion in the guidelines where that fits the component).
Focus management and keyboard navigation (Escape, arrow keys, roving tabindex, and the rest) are owned by the consumer components that use swc-popover (menu, listbox, tooltip, and similar), not by the popover host. The host does not implement dismissing with Escape, focus return, or focus trap by default. For anchored UIs, wire behavior from the pattern you are shipping (menubutton, combobox) in those parents. For modals and dialogs (popover styles only, not this host), use the dialog (modal) pattern and your app’s overlay and focus tools. The swc-popover host is not a prescribed “tab to the popover” target; focus belongs on triggers and interactive descendants per the pattern the parent component implements.
The template one-sentence “Not focusable. Keyboard navigation should skip this component and move to the next focusable element.” is for static decoration (for example Divider). It does not apply here: this host is a positioning shell; slotted controls are focusable when the composed pattern requires it—the guidance above replaces that boilerplate (no separate “Not focusable” subsection).
| Kind of test | What to check |
|---|---|
Unit (when swc-popover exists) |
No surprise default role or aria-* on the host. Placement + RTL does not make non-text chrome unperceivable (1.4.11). |
| aXe + Storybook | For swc-popover: assert ARIA on slotted children (combobox listbox, menu, etc.). For modal or dialog that only uses shared popover styles (not the swc-popover host): assert the dialog pattern (role="dialog" or alertdialog, aria-modal, focus)—the host is inapplicable there. |
| E2E (if the repo has them) | 1st-gen–relevant: nested overlay focus (see SWC-933 / SWC-932), RTL tip (SWC-917). |
Does not apply as a mandatory extra gate on the unstyled or lorem-only swc-popover story. Automated aXe on the host shell alone is of limited value; meaningful checks run on composed stories (for example Playwright accessibility testing for combobox + swc-popover, and separately for modal / dialog stories that use popover styles without the swc-popover host).
Does not apply as a required screen reader testing pass for the host with no real content (scaffold-only stories are not an end user task). Use the screen reader guide for composed patterns: swc-popover with menu or listbox; modals and dialogs use popover styles on the surface and a separate modal / dialog pattern (not the swc-popover host).
- Consumer guide and 1st-gen deprecation (SWC-2003, SWC-1227) explain shared popover styles vs
swc-popover, and what accessibility the product still owns. - SWC-1994 and Storybook (SWC-2002 if used) state no default ARIA / focus / keyboard on
swc-popover, and link to the Semantic HTML and ARIA and APG-aligned composed examples. - Visual and RTL tip placement (SWC-917) does not regress in 2nd-gen.