Skip to content

Conversation

SimonSelg
Copy link
Contributor

@SimonSelg SimonSelg commented Sep 23, 2025

sIssue describing the problem and the root cause: #8907

This PR fixes the problem I described in detail in the issue linked above. Please note that there is another strategy to fix this, which I outlined in the issue as well.

✅ Pull Request Checklist:

  • Included link to corresponding React Spectrum GitHub Issue.
  • Added/updated unit tests and storybook for this change (for new code or code which already has tests).
  • Filled out test instructions.
  • Updated documentation (if it already exists for this component).
  • Looked at the Accessibility Practices for this feature - Aria Practices

📝 Test Instructions:

Refer to the linked issue, which includes detailed reproduction instructions.

Short version:

  • Open the story called Combo Box List Box Item With Aria Label and activate VoiceOver.
  • Then interact with the ComboBox and its options via Keyboard
  • Verify that VoiceOver reads to names specified via aria-label instead of the one specified via textValue.

Copy link
Member

@snowystinger snowystinger left a comment

Choose a reason for hiding this comment

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

thanks for catching that and starting a PR!

node.rendered = rendered;
node.render = render;
node.value = value;
if (obj['aria-label']) {
Copy link
Member

Choose a reason for hiding this comment

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

generally we try to add as little as possible to these nodes, so I think we'd prefer the other option and read from focusedItem.props['aria-label'] and section.props['aria-label']

Copy link
Contributor Author

@SimonSelg SimonSelg Sep 24, 2025

Choose a reason for hiding this comment

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

Alright. Just to clarify, the attribute aria-label already on the node, it is just not initialized:

export class CollectionNode<T> implements Node<T> {
static readonly type: string;
readonly type: string;
readonly key: Key;
readonly value: T | null = null;
readonly level: number = 0;
readonly hasChildNodes: boolean = false;
readonly rendered: ReactNode = null;
readonly textValue: string = '';
readonly 'aria-label'?: string = undefined;
readonly index: number = 0;
readonly parentKey: Key | null = null;
readonly prevKey: Key | null = null;
readonly nextKey: Key | null = null;
readonly firstChildKey: Key | null = null;
readonly lastChildKey: Key | null = null;
readonly props: any = {};
readonly render?: (node: Node<any>) => ReactElement;
readonly colSpan: number | null = null;
readonly colIndex: number | null = null;

There seems to be a good part of the codebase that is reading aria-label directly from the node, see ListBoxOption.tsx, MenuSection.tsx ...

Would you still prefer the other way (read from focusedItem.props['aria-label'] and section.props['aria-label']) ? In that case I'd suggest to remove the aria-label attribute from the node class altogether and migrate all usages to node.props?.['aria-label'].

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just a small note, I removed the if condition i originally had here to ensure that the sync performed by setProps also works if the react-aria prop changes from a value to undefined.

See https://github.com/adobe/react-spectrum/compare/5a6251896b55a27807bef2630208bfb96a6657df..a11dcf8bb46322cad7d775e3ff27e98b0fc6667f#diff-11dea92f1a0629c980fc22a1e00bf0cebed068aff25abf42c47264618fce3cc6

Copy link
Member

Choose a reason for hiding this comment

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

There seems to be a good part of the codebase that is reading aria-label directly from the node

O, thank you, I'd missed that. Will follow it up with the team and see why we are doing that.

Copy link
Member

Choose a reason for hiding this comment

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

just to update, this was mainly a backcompat addition between the new collections implementation and the old collections implementation which originally added aria-label to the node directly. We'll want to keep aria-label on the node class but reading it from props is fine

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks for the update and the additional context 👍 appreciate it.

@snowystinger
Copy link
Member

note, you'll need to sign the CLA https://react-spectrum.adobe.com/contribute.html#contributor-license-agreement

@SimonSelg
Copy link
Contributor Author

I've signed the CLA 👍

@SimonSelg SimonSelg force-pushed the fix-combobox-item-aria-label branch from 5a62518 to a11dcf8 Compare September 24, 2025 09:40
@SimonSelg
Copy link
Contributor Author

SimonSelg commented Sep 30, 2025

@snowystinger any updates, do you need anything from me to continue here? happy to hear from you

I rebased on latest main.

This can be used to check whether the screen-reader announcement for option selections reads the correct label for each option, especially on mac, where there is a special codepath for this.
This commit ensures the aria-label prop from the ListItem is read into the corresponding attribute ElementNode
@SimonSelg SimonSelg force-pushed the fix-combobox-item-aria-label branch from a11dcf8 to 7e694f6 Compare September 30, 2025 08:04
@snowystinger
Copy link
Member

any updates, do you need anything from me to continue here? happy to hear from you

Not yet, we're in the middle of release testing, so apologies if we move a little slowly.

@LFDanLu LFDanLu changed the title Fix Combobox VoiceOver announcement not respecting aria-label of ListBoxItem fix: Combobox VoiceOver announcement not respecting aria-label of ListBoxItem Oct 6, 2025
LFDanLu
LFDanLu previously approved these changes Oct 6, 2025
Copy link
Member

@LFDanLu LFDanLu left a comment

Choose a reason for hiding this comment

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

Tested locally in VO, verified the announcement came though properly, thanks for fixing this!

@LFDanLu LFDanLu added this pull request to the merge queue Oct 6, 2025
Merged via the queue into adobe:main with commit 9bf119b Oct 6, 2025
31 checks passed
@SimonSelg
Copy link
Contributor Author

Thanks for getting this merged and taking the time to make an informed decision about that.

devongovett pushed a commit that referenced this pull request Oct 9, 2025
…ListBoxItem` (#8908)

* add ComboBox Story for ListBoxItem with aria-label

This can be used to check whether the screen-reader announcement for option selections reads the correct label for each option, especially on mac, where there is a special codepath for this.

* fix `CollectionBuilder` to handle `aria-label` correctly

This commit ensures the aria-label prop from the ListItem is read into the corresponding attribute ElementNode

* only add key if it exists

---------

Co-authored-by: Robert Snow <rsnow@adobe.com>
Co-authored-by: Robert Snow <snowystinger@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants