Skip to content

fix(core): expose bodyRole + bodyAriaLabelledBy inputs on fd-popover (#14260)#14270

Open
droshev wants to merge 13 commits into
mainfrom
fix/popover-body-role-input
Open

fix(core): expose bodyRole + bodyAriaLabelledBy inputs on fd-popover (#14260)#14270
droshev wants to merge 13 commits into
mainfrom
fix/popover-body-role-input

Conversation

@droshev

@droshev droshev commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Fixes #14260

Summary

Exposes bodyRole and bodyAriaLabelledBy as template inputs on <fd-popover> so consumers can set the correct ARIA role without going through the imperative PopoverConfig path.

Background: PR #12907 changed PopoverBodyComponent._bodyRole default from null'dialog' to fix screen reader announcements. However, bodyRole was only settable via PopoverConfig (imperative API). Template consumers (<fd-popover> in HTML) had no way to override it.

This PR: Adds template inputs so all consumers can set the correct role:

<fd-popover [bodyRole]="'region'" [bodyAriaLabelledBy]="'header-id'">

Default behavior unchanged. All 94 existing popover consumers remain byte-identical: bodyRole defaults to 'dialog'. null is reachable — [bodyRole]="null" renders no role attribute at all, which is the correct ARIA shape for non-modal disclosure widgets where the trigger's aria-haspopup already carries the relationship.

Changes

Primitive surface (<fd-popover>)

  • bodyRole = input<PopoverBodyRole | (string & {}) | null>('dialog') — new input with type union for autocomplete + escape hatch
  • bodyAriaLabelledBy = input<string | null>(null) — new input
  • PopoverBodyRole type exported: 'dialog' | 'region' | 'menu' | 'listbox' | 'tooltip' | 'alertdialog'
  • Wired through _effectiveConfigPopoverService.refreshConfigurationPopoverBodyComponent signals
  • bodyRole read path trusts the input directly (no ?? cfg ?? 'dialog' fallback chain — that would swallow explicit null). Sibling inputs (bodyAriaLabel, bodyAriaLabelledBy) keep the chain since their default is null and fall-through is meaningful.

Consumer patches

  • fd-form-input-message-group: binds [bodyAriaLabel] to new i18n key coreFormInputMessageGroup.popoverAriaLabel
  • fdp-input-message-group: binds [bodyAriaLabel] to new i18n key platformInputMessageGroup.popoverAriaLabel

Out of scope (filed separately)

A follow-up audit will (a) classify the remaining 92 popover consumers by ARIA semantics (disclosure → null, listbox → 'listbox', menu → 'menu', region → 'region' + name, true dialog → 'dialog' + name) and (b) flip bodyRole's default from 'dialog' to null. Bundling that into this PR would balloon the diff and force a 94-consumer baseline regen.

@droshev droshev changed the title fix(core): expose bodyRole + bodyAriaLabelledBy inputs on fd-popover (#14260) [WIP]fix(core): expose bodyRole + bodyAriaLabelledBy inputs on fd-popover (#14260) Jun 9, 2026
@netlify

netlify Bot commented Jun 9, 2026

Copy link
Copy Markdown

Deploy Preview for fundamental-ngx ready!

Name Link
🔨 Latest commit 422486e
🔍 Latest deploy log https://app.netlify.com/projects/fundamental-ngx/deploys/6a2b02be01147f00081e352a
😎 Deploy Preview https://deploy-preview-14270--fundamental-ngx.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@droshev droshev added this to the Sprint 159 - June 2026 milestone Jun 9, 2026
@droshev droshev self-assigned this Jun 9, 2026
@droshev droshev temporarily deployed to i18n-automation June 10, 2026 09:36 — with GitHub Actions Inactive
@droshev droshev changed the title [WIP]fix(core): expose bodyRole + bodyAriaLabelledBy inputs on fd-popover (#14260) fix(core): expose bodyRole + bodyAriaLabelledBy inputs on fd-popover (#14260) Jun 10, 2026
@droshev droshev force-pushed the fix/popover-body-role-input branch from 5594e71 to 2c1e0c1 Compare June 10, 2026 10:53
@droshev droshev temporarily deployed to i18n-automation June 10, 2026 10:53 — with GitHub Actions Inactive
@github-actions

github-actions Bot commented Jun 10, 2026

Copy link
Copy Markdown

♿ Accessibility Report

958/958 routes passed axe-core audit

Comment thread libs/core/popover/popover.component.ts Outdated
*
* See https://www.w3.org/WAI/ARIA/apg/patterns/dialog-modal/ for guidance.
*/
readonly bodyRole = input<string | null>('dialog');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now the API documentation suggests a specific set of supported values ('dialog', 'region', 'menu', 'listbox', 'tooltip', null), but the type is string | null, which means consumers get no autocomplete, no compile-time validation, and can pass invalid values.

If those are indeed the only supported values, a union type would improve the developer experience:

type PopoverBodyRole = 'dialog' | 'region' | 'menu' | 'listbox' | 'tooltip';

readonly bodyRole = input<PopoverBodyRole | null>('dialog');

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added PopoverBodyRole union type with the 6 most common roles + (string & {}) escape hatch for edge cases like 'tree', 'status', 'alert'. Gives autocomplete without gatekeeping the ARIA spec. Also updated PopoverConfig.bodyRole for consistency

droshev and others added 10 commits June 11, 2026 14:45
…#14260)

Bind [bodyAriaLabel] using i18n key coreFormInputMessageGroup.popoverAriaLabel.
Requires CRUCIBLE Task 2.2 (i18n key registration) for full compilation.
…14260)

Bind [bodyAriaLabel] using i18n key platformInputMessageGroup.popoverAriaLabel.
Requires CRUCIBLE Task 2.2 (i18n key registration) for full compilation.
…e-group popover (#14260)

Removes 7 wizard-generator route suppressions for aria-dialog-name violations.
All suppressions were tied to #14260 and are now resolved by the fix in commit d7099a1.

Verified: all 7 routes pass aria-dialog-name rule in a11y sweep with suppressions removed.
  The nullish-coalescing fallback chain bodyRole() ?? cfg.bodyRole ?? 'dialog'
  swallowed null, making it impossible for consumers to opt out of role=dialog
  via [bodyRole]='null'. Trust the input value as authoritative — its default
  ('dialog') already handles the unbound case.
  Selectors targeted the <fd-popover-body> host element, but [attr.role],
  [attr.aria-label], [attr.aria-labelledby] are bound on the inner
  .fd-popover__body div per popover-body.component.html:14-16. Wrong
  selector returned the host (no role attr) and getAttribute returned null.
  Verify union values and escape hatch both work correctly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(core): fd-popover-body role=dialog without accessible name causes aria-dialog-name violation

3 participants