Skip to content

fix(ui5-select): fix acc finding#13559

Open
PetyaMarkovaBogdanova wants to merge 12 commits into
mainfrom
fix-acc-select
Open

fix(ui5-select): fix acc finding#13559
PetyaMarkovaBogdanova wants to merge 12 commits into
mainfrom
fix-acc-select

Conversation

@PetyaMarkovaBogdanova

@PetyaMarkovaBogdanova PetyaMarkovaBogdanova commented May 20, 2026

Copy link
Copy Markdown
Contributor

8) Select (6 failing)

  • Interactive accessibility failures in dropdown/listbox/dialog flow.
  • Repeated signals include missing accessible naming and state/role consistency checks.
Component Issue Not by spec Good to have Spec refs Spec quote sentence Coverage strength
Select Dropdown/listbox/dialog naming and role/state consistency issues Yes No ACC-253, ACC-264, ACC-270, ACC-272 "Inherit role=dialog of UI5 Dialog control with label='Select: + [Name of field]'" and "see Dialog" Direct

@ui5-webcomponents-bot

ui5-webcomponents-bot commented May 20, 2026

Copy link
Copy Markdown
Collaborator

@ui5-webcomponents-bot ui5-webcomponents-bot temporarily deployed to preview May 20, 2026 07:19 Inactive
@PetyaMarkovaBogdanova PetyaMarkovaBogdanova marked this pull request as ready for review May 20, 2026 14:29
@ui5-webcomponents-bot ui5-webcomponents-bot temporarily deployed to preview May 20, 2026 14:44 Inactive
@ui5-webcomponents-bot ui5-webcomponents-bot temporarily deployed to preview June 2, 2026 15:37 Inactive
@ui5-webcomponents-bot ui5-webcomponents-bot temporarily deployed to preview June 3, 2026 06:51 Inactive

@dobrinyonkov dobrinyonkov left a comment

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.

Thanks for picking this up — the listbox naming fix is a real improvement. Four inline comments below; (1) and (4) would be good to address before merging, (2) and (3) are polish/follow-up.

onClose={this._afterClose}
onKeyDown={this._onkeydown}
accessibleName={this._isPhone ? this._headerTitleText : undefined}
accessibleName={this._isPhone ? (this.ariaLabelText || this._headerTitleText) : undefined}

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.

Spec mismatch — missing Select: prefix (medium).

The spec quote in the PR description literally calls for "Select: + [Name of field]". This sets the mobile dialog's accessibleName to just the field name (e.g. "Country"), not "Select: Country". The dialog role already announces "dialog", so the textual Select: prefix is what distinguishes this dialog from arbitrary other dialogs in the flow — without it, screen-reader users hear "Country, dialog" and lose the cue that this is the Select's value picker.

Could you confirm with the accessibility owner whether the prefix is required? If yes, please introduce a dedicated i18n key (don't hard-code "Select: ") and use it here, roughly:

accessibleName={this._isPhone ? this._effectivePopoverAccessibleName : undefined}

where the getter applies the localized prefix to this.ariaLabelText || this._headerTitleText.

onMouseDown={this._itemMousedown}
onItemClick={this._handleItemPress}
accessibleRole="ListBox"
accessibleName={this.ariaLabelText || this._headerTitleText}

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.

Duplicated expression (low).

this.ariaLabelText || this._headerTitleText now appears on both line 30 and line 71. If the precedence ever changes (e.g. a third source is added, or the Select: prefix from comment above lands), it's two places to keep in sync. Consider extracting a getter in Select.ts

get _effectivePopoverAccessibleName() {
    return this.ariaLabelText || this._headerTitleText;
}

and using it on both lines. Matches how _headerTitleText is already factored out. Optional but tidy.

onMouseDown={this._itemMousedown}
onItemClick={this._handleItemPress}
accessibleRole="ListBox"
accessibleName={this.ariaLabelText || this._headerTitleText}

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.

Borrowed i18n key — please add a dedicated one (low).

_headerTitleText resolves to INPUT_SUGGESTIONS_TITLE ("All Items"), which was authored for the Input suggestions popover. Now that every Select listbox falls back to this string when the consumer hasn't set a label, it's being used as a Select-specific accessible name even though the key name says otherwise.

Please introduce a Select-specific i18n key (e.g. SELECT_LISTBOX_LABEL / SELECT_POPOVER_TITLE) and have _headerTitleText (or a new getter) resolve to it — even if the English string happens to match. Keeps translations correctly scoped per component and avoids surprises if Input's wording ever diverges.

onMouseDown={this._itemMousedown}
onItemClick={this._handleItemPress}
accessibleRole="ListBox"
accessibleName={this.ariaLabelText || this._headerTitleText}

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.

No test coverage added (medium).

This PR changes ARIA wiring on two surfaces but adds no test. The branch history (two fix(...): fixed failing test commits) suggests this area is easy to regress silently. Two natural assertions belong in the existing accessibility spec at packages/main/cypress/specs/Select.cy.tsx:250:

  1. Open the popover on a <Select accessibleName="Foo"> → the inner [ui5-list] has aria-label="Foo". Add a second case for accessibleNameRef and a third for a Select with no consumer label (asserting the fallback string).
  2. Simulate _isPhone → the [ui5-responsive-popover] has aria-label matching the field's accessible name.

Without these, the next refactor of SelectPopoverTemplate will not catch a regression here.

@dobrinyonkov dobrinyonkov left a comment

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.

Thanks for the iterations — all four original comments are addressed: the Select: prefix is in, the dedicated i18n keys exist, the duplication is factored into _effectivePopoverAccessibleName, and there are tests for both surfaces. Three new things worth fixing before merge, plus one nit.

&& value !== null
&& "key" in value
&& "defaultText" in value;
};

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.

The isI18nText type guard (and the two narrowed branches at lines 1058 and 1142) should be removed — it's working around a stale generated file, not a real type problem.

Generated i18n constants are always typed as I18nText (see packages/main/src/generated/i18n/i18n-defaults.ts — every key is declared const FOO: I18nText = {key, defaultText}). Sibling code in this same file just does:

return Select.i18nBundle.getText(SELECT_ROLE_DESCRIPTION);
return Select.i18nBundle.getText(FORM_SELECTABLE_REQUIRED);

no guards needed. The TS error that prompted the workaround was almost certainly because yarn generate hadn't been run after the new keys were added to messagebundle.properties, so the imports in the generated file didn't yet exist. Running yarn generate regenerates the file and the simple form compiles fine.

Leaving the guard in is bad on two counts:

  1. It's dead code (the branches are unreachable in a correctly generated build) — readers will wonder what edge case it covers.
  2. The return "" fallback at line 1062 would silently produce a Select with no listbox label and no mobile dialog label if it ever did fire — masking exactly the regression this PR is supposed to prevent.

Please remove isI18nText, the I18nText named import, and inline the getText calls in both _headerTitleText and _effectivePopoverAccessibleName.

onMouseDown={this._itemMousedown}
onItemClick={this._handleItemPress}
accessibleRole="ListBox"
accessibleName={this.ariaLabelText || this._headerTitleText}

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.

Nit: since _effectivePopoverAccessibleName exists for the popover line, the listbox line could be factored the same way — a small getter _effectiveListAccessibleName returning this.ariaLabelText || this._headerTitleText. Not critical (the two expressions now correctly differ — the popover one carries the Select: prefix), but it keeps the template uniform. Skip if you'd rather not.

.should("have.attr", "accessible-name")
.and("equal", _effectivePopoverAccessibleName);
});
});

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.

This assertion is now circular. It reads the value of _effectivePopoverAccessibleName from the element and then asserts the rendered attribute equals that same value — so if the getter is broken, both sides of the equality break the same way and the test still passes.

The other new test (Select.cy.tsx:325) hard-codes "Select: Countries" for the mobile case, so coverage isn't lost — but consider either deleting this case or changing it to assert a literal string. Either way, the property-readback pattern hides regressions.

SELECT_OPTIONS=Select Options

#XACT: ARIA announcement prefix for Select dialog accessible name on mobile (without trailing space)
SELECT_POPOVER_ACCESSIBLE_NAME_PREFIX=Select:

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.

Cleaner than embedding the space in the translation — translators can't accidentally drop trailing whitespace, and the join is done explicitly in code. Good fix. (No action needed — leaving the comment here so the rationale is visible in review.)

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.

3 participants