Fix to Improve Flyout Accessibility by Adjusting UITableViewController Labels#31619
Conversation
There was a problem hiding this comment.
Pull Request Overview
This PR improves accessibility for the Shell Flyout by addressing iOS VoiceOver announcing the flyout as a generic "table" instead of providing meaningful navigation context. The changes add semantic properties to flyout navigation items and configure proper accessibility traits for the underlying UITableViewController.
- Adds semantic properties (Description and Hint) to ShellContent items in the app template
- Configures accessibility traits and labels for the Shell flyout's UITableViewController
- Enhances button accessibility traits for flyout cells
Reviewed Changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/Templates/src/templates/maui-mobile/AppShell.xaml | Adds SemanticProperties.Description and SemanticProperties.Hint to ShellContent navigation items |
| src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/UIContainerCell.cs | Enhances accessibility by setting button traits on both platform view and cell |
| src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellTableViewController.cs | Configures flyout-specific accessibility properties for the UITableView |
src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellTableViewController.cs
Outdated
Show resolved
Hide resolved
|
/azp run MAUI-UITests-public |
|
Azure Pipelines successfully started running 1 pipeline(s). |
src/Controls/src/Core/Compatibility/Handlers/Shell/iOS/ShellTableViewController.cs
Outdated
Show resolved
Hide resolved
|
|
||
| TableView.AccessibilityTraits = UIAccessibilityTrait.None; | ||
|
|
||
| TableView.AccessibilityLabel = "Navigation Flyout Menu"; |
There was a problem hiding this comment.
Should this be localized by using resources?
There was a problem hiding this comment.
Hi @rmarinho ,I’ve updated the code with localization so the accessibility labels now read correctly in VoiceOver using language-specific strings. Please review and let me know if you have any concerns.
|
@PureWeen , The reported accessibility issue #30894 is different from the previously mentioned issue #16245. This fix specifically addresses a problem where the screen reader reads the entire Shell Flyout view as a “table.” To resolve this, we set the appropriate accessibility properties within the Issue #16245 will be addressed separately. |
PureWeen
left a comment
There was a problem hiding this comment.
i think the main thing we want here is for the keyboard navigation to just go directly to the items vs the keyboard navigation highlighting the entire table
I'll probably push back on the reporters suggestion that it needs to not read as a table.
Like, if you use the accessibility inspector on the settings menu on mac it reports as a "Column"
but when you navigate to it it just goes to the first item.
I don't think we care about setting any labels for the table itself, we just want the table to be invisible
|
/rebase |
42881db to
969afe1
Compare
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
@PureWeen , I’ve disabled the |
|
/rebase |
226bb14 to
64cde8b
Compare
|
/azp run |
|
Azure Pipelines successfully started running 3 pipeline(s). |
| TableView.ContentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentBehavior.Never; | ||
| } | ||
|
|
||
| TableView.AccessibilityElementsHidden = true; |
There was a problem hiding this comment.
This change hides ALL children of the TableView from VoiceOver, expected behavior?
f18f531 to
1a28560
Compare
Review Feedback: PR #31619 - Fix to Improve Flyout AccessibilityRecommendation✅ Approve with Suggestions Recommended changes (non-blocking):
📋 Full PR Review DetailsSummaryThis PR fixes a critical accessibility issue (#30894) where the Shell Flyout on iOS/MacCatalyst is announced by screen readers as a "table" instead of a navigation menu. The fix replaces the default Code ReviewThe Problem (Root Cause Analysis)
Why This Fix Is CorrectThe PR takes the right approach for several reasons:
Code Quality AssessmentStrengths:
Potential concerns addressed:
PublicAPI Changes✅ PublicAPI entries are correct: override Microsoft.Maui.Controls.Platform.Compatibility.ShellTableViewController.LoadView() -> void
Test CoverageWhy this is a concern:
What a test would look like: A UI test should:
Mitigation: The issue (#30894) is marked with Manual Testing EvidenceThe PR includes video evidence showing:
The contributor responded to maintainer questions with additional testing, showing iterative validation. Edge Cases AnalysisTested implicitly (likely works):
Not explicitly tested (should verify):
Risk assessment: Low - these edge cases would likely work because:
Template Changes Analysis<ShellContent
Title="Dashboard"
Icon="{StaticResource IconDashboard}"
ContentTemplate="{DataTemplate pages:MainPage}"
Route="main"
SemanticProperties.Description="Dashboard"
SemanticProperties.Hint="Navigate to dashboard"/>✅ These changes are good practice:
But current implementation is acceptable and follows common patterns. Security & Privacy✅ No security concerns - purely UI accessibility fix Issues FoundNone (Must Fix)No critical issues found. The implementation is sound. Suggestions (Non-blocking)
Approval Checklist
Final AssessmentThis is a well-executed fix that solves a real accessibility problem. The approach is correct, the implementation is clean, and the PR shows good iteration based on maintainer feedback. The contributor clearly understands both the problem domain (iOS accessibility) and the solution space (UIAccessibilityContainerType). The only gap is lack of automated testing, but given the difficulty of testing VoiceOver behavior programmatically and the existence of manual validation, this is acceptable for merge. Future work could add accessibility assertions if .NET MAUI adds testing infrastructure for iOS accessibility APIs. Recommendation: Approve and merge. This improves accessibility for all .NET MAUI apps using Shell on iOS/MacCatalyst. Review Metadata
Summary for MaintainersTL;DR: This PR correctly fixes the accessibility issue using Key points:
|
…r Labels (#31619) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Description: The Shell Flyout is implemented using a `UITableViewController` with a `UITableView`, which iOS accessibility services announce as a "table". ### Description of Change: Entirely hides the UITableView Accessibility and makes the UIContainerCell to become a first responder, The inner UIContainerCell cannot be individually detected — it is treated as a single grouped element. ### Issues Fixed Fixes #30894 ### Tested the behaviour in the following platforms - [ ] Android - [ ] Windows - [ ] iOS - [x] Mac ### Output Screenshot Before Issue Fix | After Issue Fix | |----------|----------| |<video width="300" height="150" alt="Before Fix" src="https://github.com/user-attachments/assets/1862862a-ffee-4302-a46f-5ac083e39a0b">|<video width="300" height="150" alt="After Fix" src ="https://github.com/user-attachments/assets/be969437-d5ea-4319-ac19-9b60bd0e1a68">|
…r Labels (#31619) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Description: The Shell Flyout is implemented using a `UITableViewController` with a `UITableView`, which iOS accessibility services announce as a "table". ### Description of Change: Entirely hides the UITableView Accessibility and makes the UIContainerCell to become a first responder, The inner UIContainerCell cannot be individually detected — it is treated as a single grouped element. ### Issues Fixed Fixes #30894 ### Tested the behaviour in the following platforms - [ ] Android - [ ] Windows - [ ] iOS - [x] Mac ### Output Screenshot Before Issue Fix | After Issue Fix | |----------|----------| |<video width="300" height="150" alt="Before Fix" src="https://github.com/user-attachments/assets/1862862a-ffee-4302-a46f-5ac083e39a0b">|<video width="300" height="150" alt="After Fix" src ="https://github.com/user-attachments/assets/be969437-d5ea-4319-ac19-9b60bd0e1a68">|
…r Labels (#31619) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Description: The Shell Flyout is implemented using a `UITableViewController` with a `UITableView`, which iOS accessibility services announce as a "table". ### Description of Change: Entirely hides the UITableView Accessibility and makes the UIContainerCell to become a first responder, The inner UIContainerCell cannot be individually detected — it is treated as a single grouped element. ### Issues Fixed Fixes #30894 ### Tested the behaviour in the following platforms - [ ] Android - [ ] Windows - [ ] iOS - [x] Mac ### Output Screenshot Before Issue Fix | After Issue Fix | |----------|----------| |<video width="300" height="150" alt="Before Fix" src="https://github.com/user-attachments/assets/1862862a-ffee-4302-a46f-5ac083e39a0b">|<video width="300" height="150" alt="After Fix" src ="https://github.com/user-attachments/assets/be969437-d5ea-4319-ac19-9b60bd0e1a68">|
…r Labels (#31619) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Description: The Shell Flyout is implemented using a `UITableViewController` with a `UITableView`, which iOS accessibility services announce as a "table". ### Description of Change: Entirely hides the UITableView Accessibility and makes the UIContainerCell to become a first responder, The inner UIContainerCell cannot be individually detected — it is treated as a single grouped element. ### Issues Fixed Fixes #30894 ### Tested the behaviour in the following platforms - [ ] Android - [ ] Windows - [ ] iOS - [x] Mac ### Output Screenshot Before Issue Fix | After Issue Fix | |----------|----------| |<video width="300" height="150" alt="Before Fix" src="https://github.com/user-attachments/assets/1862862a-ffee-4302-a46f-5ac083e39a0b">|<video width="300" height="150" alt="After Fix" src ="https://github.com/user-attachments/assets/be969437-d5ea-4319-ac19-9b60bd0e1a68">|
…r Labels (#31619) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Description: The Shell Flyout is implemented using a `UITableViewController` with a `UITableView`, which iOS accessibility services announce as a "table". ### Description of Change: Entirely hides the UITableView Accessibility and makes the UIContainerCell to become a first responder, The inner UIContainerCell cannot be individually detected — it is treated as a single grouped element. ### Issues Fixed Fixes #30894 ### Tested the behaviour in the following platforms - [ ] Android - [ ] Windows - [ ] iOS - [x] Mac ### Output Screenshot Before Issue Fix | After Issue Fix | |----------|----------| |<video width="300" height="150" alt="Before Fix" src="https://github.com/user-attachments/assets/1862862a-ffee-4302-a46f-5ac083e39a0b">|<video width="300" height="150" alt="After Fix" src ="https://github.com/user-attachments/assets/be969437-d5ea-4319-ac19-9b60bd0e1a68">|
…r Labels (#31619) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Description: The Shell Flyout is implemented using a `UITableViewController` with a `UITableView`, which iOS accessibility services announce as a "table". ### Description of Change: Entirely hides the UITableView Accessibility and makes the UIContainerCell to become a first responder, The inner UIContainerCell cannot be individually detected — it is treated as a single grouped element. ### Issues Fixed Fixes #30894 ### Tested the behaviour in the following platforms - [ ] Android - [ ] Windows - [ ] iOS - [x] Mac ### Output Screenshot Before Issue Fix | After Issue Fix | |----------|----------| |<video width="300" height="150" alt="Before Fix" src="https://github.com/user-attachments/assets/1862862a-ffee-4302-a46f-5ac083e39a0b">|<video width="300" height="150" alt="After Fix" src ="https://github.com/user-attachments/assets/be969437-d5ea-4319-ac19-9b60bd0e1a68">|
…r Labels (#31619) <!-- Please let the below note in for people that find this PR --> > [!NOTE] > Are you waiting for the changes in this PR to be merged? > It would be very helpful if you could [test the resulting artifacts](https://github.com/dotnet/maui/wiki/Testing-PR-Builds) from this PR and let us know in a comment if this change resolves your issue. Thank you! <!-- !!!!!!! MAIN IS THE ONLY ACTIVE BRANCH. MAKE SURE THIS PR IS TARGETING MAIN. !!!!!!! --> ### Issue Description: The Shell Flyout is implemented using a `UITableViewController` with a `UITableView`, which iOS accessibility services announce as a "table". ### Description of Change: Entirely hides the UITableView Accessibility and makes the UIContainerCell to become a first responder, The inner UIContainerCell cannot be individually detected — it is treated as a single grouped element. ### Issues Fixed Fixes #30894 ### Tested the behaviour in the following platforms - [ ] Android - [ ] Windows - [ ] iOS - [x] Mac ### Output Screenshot Before Issue Fix | After Issue Fix | |----------|----------| |<video width="300" height="150" alt="Before Fix" src="https://github.com/user-attachments/assets/1862862a-ffee-4302-a46f-5ac083e39a0b">|<video width="300" height="150" alt="After Fix" src ="https://github.com/user-attachments/assets/be969437-d5ea-4319-ac19-9b60bd0e1a68">|
## What's Coming .NET MAUI inflight/candidate introduces significant improvements across all platforms with focus on quality, performance, and developer experience. This release includes 16 commits with various improvements, bug fixes, and enhancements. ## Checkbox - [Android] Implement material3 support for CheckBox by @HarishwaranVijayakumar in #33339 <details> <summary>🔧 Fixes</summary> - [Implement Material3 Support for CheckBox](#33338) </details> ## CollectionView - [Android] Fixed EmptyView doesn’t display when CollectionView is placed inside a VerticalStackLayout by @NanthiniMahalingam in #33134 <details> <summary>🔧 Fixes</summary> - [CollectionView does not show an EmptyView template with an empty collection](#32932) </details> ## Essentials - [Windows]Fix NullReferenceException in OpenReadAsync for FileResult created with full path by @devanathan-vaithiyanathan in #28238 <details> <summary>🔧 Fixes</summary> - [[Windows] FileResult(string fullPath) not initialized properly](#26858) </details> ## Image - Fix Glide IllegalArgumentException in MauiCustomTarget.clear() for destroyed activities by @jfversluis via @Copilot in #29780 <details> <summary>🔧 Fixes</summary> - [java.lang.IllegalArgumentException: You cannot start a load for a destroyed activity - glide](#29699) </details> ## Label - [Android] Fix for Label WordWrap width issue causing HorizontalOptions misalignment by @praveenkumarkarunanithi in #33281 <details> <summary>🔧 Fixes</summary> - [[Android] Unexpected Line Breaks in Android, Label with WordWrap Mode Due to Trailing Space.](#31782) - [Label not sized correctly on Android](#27614) </details> - Fix to Improve Flyout Accessibility by Adjusting UITableViewController Labels by @SuthiYuvaraj in #31619 <details> <summary>🔧 Fixes</summary> - [Navigation section present under hamburger are programmatically define as table :A11y_.NET maui_User can get all the insights of Dashboard_Devtools](#30894) </details> ## Mediapicker - [Regression][iOS] Fix MediaPicker PickPhotosAsync getting file name in contentType property by @devanathan-vaithiyanathan in #33390 <details> <summary>🔧 Fixes</summary> - [[iOS] MediaPicker PickPhotosAsync getting file name in contentType property](#33348) </details> ## Navigation - Fix handler not disconnected when removing non visible pages using RemovePage() by @Vignesh-SF3580 in #32289 <details> <summary>🔧 Fixes</summary> - [NavigationPage.Navigation.RemovePage() fails to disconnect handlers when removing pages, unlike ContentPage.Navigation.RemovePage()](#32239) </details> ## Picker - [Android] Fix Picker IsOpen not reset when picker is dismissed by @devanathan-vaithiyanathan in #33332 <details> <summary>🔧 Fixes</summary> - [[Android] Picker IsOpen not reset when picker is dismissed](#33331) </details> ## Shell - [iOS & Catalyst ] Fixed IsEnabled property should work on Tabs by @SubhikshaSf4851 in #33369 <details> <summary>🔧 Fixes</summary> - [[Catalyst] TabBarBackgroundColor, TabBarUnselectedColor, and IsEnabled Not Working as Expected in Shell](#33158) </details> - [iOS,Windows] Fix navigation bar colors not resetting when switching ShellContent by @Vignesh-SF3580 in #33228 <details> <summary>🔧 Fixes</summary> - [[iOS, Windows] Shell Navigation bar colors are not updated correctly when switching ShellContent](#33227) </details> - [iOS] Fixed Shell navigation on search handler suggestion selection by @SubhikshaSf4851 in #33406 <details> <summary>🔧 Fixes</summary> - [[iOS] Clicking on search suggestions fails to navigate to detail page correctly](#33356) </details> ## Templates - Fix VoiceOver doesnot announces the State of the ComboBox by @SuthiYuvaraj in #32286 ## Xaml - [XSG][BindingSourceGen] Add support for CommunityToolkit.Mvvm ObservablePropertyAttribute by @simonrozsival via @Copilot in #33028 <details> <summary>🔧 Fixes</summary> - [[XSG] Add heuristic to support bindable properties generated by other source generators](#32597) </details> <details> <summary>📦 Other (2)</summary> - [XSG] Improve diagnostic reporting during binding compilation by @simonrozsival via @Copilot in #32905 - [Testing] Fixed Test case failure in PR 33574 - [01/19/2026] Candidate - 1 by @TamilarasanSF4853 in #33602 </details> **Full Changelog**: main...inflight/candidate
Note
Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!
Issue Description:
The Shell Flyout is implemented using a
UITableViewControllerwith aUITableView, which iOS accessibility services announce as a "table".Description of Change:
Entirely hides the UITableView Accessibility and makes the UIContainerCell to become a first responder, The inner UIContainerCell cannot be individually detected — it is treated as a single grouped element.
Issues Fixed
Fixes #30894
Tested the behaviour in the following platforms
Output Screenshot
BeforeFixAccess.mov
AfterFixAccess.mov