Revamp A11y for Web platform#3016
Conversation
…or the Youtrack issues
…eral problems with popups and allows for better separation of concerns
…wners side with these child nodes
…. The tree is not redo on each invalidation, instead we track changes and sync periodically. This allows for better performance and more accurate a11y since browser can diff the tree better. Fixed issues with how certain roles were not being applied.
…nd bounds items so that ScreenReader can traverse elements by focusing them. Fixes https://youtrack.jetbrains.com/issue/CMP-8627/Web-A11y.-Voice-over.-Scroll-doesnt-work (succesfully tested on my iphone 15)
| val webSemanticsRoot: HTMLElement, | ||
| ) : PlatformContext.SemanticsOwnerListener { | ||
|
|
||
| private val invalidationChannel = |
There was a problem hiding this comment.
I see a good part of this file moved to the new ComposeWebSemanticsOwner.
Do you think it's possible to convert this ComposeWebSemanticsListener into ComposeWebSemanticsOwner? To rename the file and amend it, so the git diff would become more granular to preserve the history of this file and so it's easier to see what changed and what not?
There was a problem hiding this comment.
Do you mean to: with ComposeWebSemanticsListener old file (before PR) to be renamed to ComposeWebSemanticsOwner and add all of the PR's ComposeWebSemanticsOwner new content into it. Then create a new ComposeWebSemanticsListener that implements the listener??? This way all most code change can be seen in the renamed file and what has changed so that it is easier to track vs ComposeWebSemanticsListener having so low code that it is better create a new file for it because it is easier to track changes???
I'm still doing changes to fix to rough edges with the PR and I might open a new one replacing this. making it draft |
Redone the whole A11y for Web platform. Separated SemanticsOwnerListener from WebSemanticOwner and WebSemanticNode.
Compose can have several SemanticOwners (the main one + all the popups and dialogs) so thats why now, SemanticsOwnerListener holds a list of the owners. The callbacks signaling semantic changes filter them by the SemanticNode they are referring to and then invoke the WebSemanticOwner specific functions. Each WebSemanticOwner has its own Channels for tracking invalidation (this way it is much easier to have a more fine grained control over what we dispose, create, update, etc...).
Then there is WebSemanticNode (which is a wrapper around SemanticNode) that contains the backing html element it is referring to and more info related to its handling.
When WebSemanticOwner receives an invalidation there is some debounce (same logic as before) and if it syncs, instead of recreating the whole accessibility dom tree, I update positions (if needed) in the html elements, its data and its layout info (like Bounds, position, etc... only if changed!!). This makes the whole synchronization way more performant as it also prevents html layout reflows (which causes major slowdowns).
Attributes are moved to js interop blocks to avoid the constant wasm2js boundary crossing for objects that don't need it (eg: attribute names, attributes setter groups, especially string related crossings). Now, when syncing, values are compared to previous ones to check whether we need an update to the node or not.
I have also fixed several issues of missing features: a11y nodes that were not working as expected, added more information to html elements, added a couple of roles in web (+fixed some issue due to the timing on when the role was being specified, which caused certain roles to change to Button role even though they had a more specific role); the tree is now correctly ordered by indexTraversal and by its geometric position; scrolling with VoiceOver works as expected
I have tried to mimic what other Compose platforms do, especially IOS. There might still be some bugs regarding missing data or the way nodes are merged but overall, I have added most of the a11y features
Fixes CMP-8612, CMP-8614, CMP-9368, CMP-8628, CMP-8624, CMP-8619, CMP-8621, CMP-8627


Before
After



ScreenRecording_04-24-2026.14-44-50_1.MP4
trim.B9DD9CAE-6312-4FDB-BAE8-94F10EDEDB49.MOV
Testing
Manually, existing tests pass
This should be tested by QA
Release Notes
Fixes - Web