[iOS] Fix VoiceOver focus not shifting to Picker/DatePicker/TimePicker popups#33152
[iOS] Fix VoiceOver focus not shifting to Picker/DatePicker/TimePicker popups#33152PureWeen merged 1 commit intodotnet:inflight/currentfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR improves VoiceOver accessibility for Picker, DatePicker, and TimePicker on iOS by adding accessibility focus notifications that inform VoiceOver when picker popups appear and close, ensuring proper focus management for screen reader users.
Key Changes
- Added two extension methods to
SemanticExtensions.csfor posting VoiceOver accessibility notifications - Integrated accessibility notifications in picker handlers to announce when pickers open and close
- Ensured focus returns to the original control when picker popups dismiss
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
src/Core/src/Platform/iOS/SemanticExtensions.cs |
Added PostAccessibilityFocusNotification extension methods to post VoiceOver screen changed notifications for picker controls and input views |
src/Core/src/Handlers/DatePicker/DatePickerHandler.iOS.cs |
Integrated accessibility notifications in OnStarted and OnEnded methods to announce date picker popup state changes |
src/Core/src/Handlers/TimePicker/TimePickerHandler.iOS.cs |
Integrated accessibility notifications in OnStarted and OnEnded methods to announce time picker popup state changes |
src/Core/src/Handlers/Picker/PickerHandler.iOS.cs |
Integrated accessibility notifications for both standard iOS picker and MacCatalyst alert-based picker implementations |
🤖 PR Agent Review📊 Expand Full ReviewStatus: ✅ APPROVE
🔍 Phase 1: Pre-Flight — Context & Validation📝 Review Session — Improve pr-comment skill: prevent duplicates, mirror state file structure ·
|
| # | Source | Approach | Test Result | Files Changed | Notes |
|---|---|---|---|---|---|
| PR | PR #33152 | Adds PostAccessibilityFocusNotification() extension methods in SemanticExtensions.cs. Calls from EditingDidBegin (focus popup) and EditingDidEnd (restore focus) events in PickerHandler, DatePickerHandler, TimePickerHandler. |
✅ PASS (Gate) | SemanticExtensions.cs (+46), PickerHandler.iOS.cs (+24/-2), DatePickerHandler.iOS.cs (+13), TimePickerHandler.iOS.cs (+16) | Correct iOS accessibility pattern. Extension methods handle Window null check and main thread dispatch. |
Exhausted: N/A (iOS API requirement - no alternatives to explore)
Selected Fix: PR's fix - This is the correct and only way to fix VoiceOver focus on iOS. The PR properly implements the iOS accessibility pattern using UIAccessibility.PostNotification, follows MAUI conventions with extension methods, and handles edge cases (null window, main thread dispatch).
📋 Phase 5: Report — Final Recommendation
📝 Review Session — Improve pr-comment skill: prevent duplicates, mirror state file structure · e3a9bd4
Status: ✅ COMPLETE
PR Finalization
Title: ✅ Excellent - "[iOS] Fix VoiceOver focus not shifting to Picker/DatePicker/TimePicker popups"
Description Recommendations:
⚠️ Add required NOTE block for testing PR artifacts⚠️ Remove "Draft PR until include some related tests" (tests now included)⚠️ Add root cause explanation for future reference
Recommended Updated Description:
<!-- 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!
### Description of Change
This PR fixes VoiceOver accessibility on iOS for Picker, DatePicker, and TimePicker controls. When picker popups open/close, VoiceOver now properly shifts focus using iOS accessibility notifications.
**Root cause:** VoiceOver on iOS requires explicit focus notifications via `UIAccessibility.PostNotification(ScreenChanged, view)` when modal UI appears or dismisses. Without these notifications, VoiceOver doesn't know to shift focus, leaving users navigating background controls instead of the picker popup.
**Fix:**
- Adds `PostAccessibilityFocusNotification()` extension methods in `SemanticExtensions.cs`
- Posts `ScreenChanged` notification when picker popups open (in `EditingDidBegin` event)
- Posts `ScreenChanged` notification to restore focus when popups close (in `EditingDidEnd` event)
- Handles edge cases: null window checks, main thread dispatch for delayed InputView availability
**Tests:** UI tests created in `Issue30746.xaml[.cs]` and marked with `ManualReview` category since VoiceOver focus cannot be automated with Appium. Manual testing with VoiceOver enabled confirms proper focus behavior.
### Issues Fixed
Fixes #30746Code Review Notes
Inline Suggestions (from Copilot):
- PickerHandler.iOS.cs:109 - Add space after
ifkeyword ✓ Minor style - PickerHandler.iOS.cs:113 - Move
PostAccessibilityFocusNotification()inside if block ✓ Good suggestion - should only post if view controller presented - Trailing whitespace in TimePickerHandler ✓ Minor cleanup
Recommended: Apply Copilot's inline suggestions before merging.
Final Recommendation
✅ APPROVE with minor suggestions
This PR correctly implements the iOS accessibility pattern for VoiceOver focus management. The implementation is sound, follows MAUI conventions, and properly handles edge cases.
Before merging:
- Update PR description with NOTE block and remove "Draft" status
- Apply inline code suggestions (spacing, move notification call)
- Consider manual VoiceOver testing to confirm behavior
|
/rebase |
5c973f4 to
025c221
Compare
PureWeen
left a comment
There was a problem hiding this comment.
the behavior of this one is causing the pickers to act a bit erratic.
If I go into a picker and then leave it loses focus completely from the entry and the user will lose their place.
I've pushed up the sandbox app I was testing with
981bbb3 to
37340a4
Compare
…r popups (#33152) <!-- 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! ### Description of Change This PR fixes VoiceOver accessibility on iOS for Picker, DatePicker, and TimePicker controls. When picker popups open/close, VoiceOver now properly shifts focus using iOS accessibility notifications. **Root cause:** VoiceOver on iOS requires explicit focus notifications via `UIAccessibility.PostNotification(ScreenChanged, view)` when modal UI appears or dismisses. Without these notifications, VoiceOver doesn't know to shift focus, leaving users navigating background controls instead of the picker popup. **Fix:** - Adds `PostAccessibilityFocusNotification()` extension methods in `SemanticExtensions.cs` - Posts `ScreenChanged` notification when picker popups open (in `EditingDidBegin` event) - Posts `ScreenChanged` notification to restore focus when popups close (in `EditingDidEnd` event) - Handles edge cases: null window checks, main thread dispatch for delayed InputView availability **Tests:** UI tests created in `Issue30746.xaml[.cs]` and marked with `ManualReview` category since VoiceOver focus cannot be automated with Appium. Manual testing with VoiceOver enabled confirms proper focus behavior. ### Issues Fixed Fixes #30746
…r popups (#33152) <!-- 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! ### Description of Change This PR fixes VoiceOver accessibility on iOS for Picker, DatePicker, and TimePicker controls. When picker popups open/close, VoiceOver now properly shifts focus using iOS accessibility notifications. **Root cause:** VoiceOver on iOS requires explicit focus notifications via `UIAccessibility.PostNotification(ScreenChanged, view)` when modal UI appears or dismisses. Without these notifications, VoiceOver doesn't know to shift focus, leaving users navigating background controls instead of the picker popup. **Fix:** - Adds `PostAccessibilityFocusNotification()` extension methods in `SemanticExtensions.cs` - Posts `ScreenChanged` notification when picker popups open (in `EditingDidBegin` event) - Posts `ScreenChanged` notification to restore focus when popups close (in `EditingDidEnd` event) - Handles edge cases: null window checks, main thread dispatch for delayed InputView availability **Tests:** UI tests created in `Issue30746.xaml[.cs]` and marked with `ManualReview` category since VoiceOver focus cannot be automated with Appium. Manual testing with VoiceOver enabled confirms proper focus behavior. ### Issues Fixed Fixes #30746
…r popups (#33152) <!-- 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! ### Description of Change This PR fixes VoiceOver accessibility on iOS for Picker, DatePicker, and TimePicker controls. When picker popups open/close, VoiceOver now properly shifts focus using iOS accessibility notifications. **Root cause:** VoiceOver on iOS requires explicit focus notifications via `UIAccessibility.PostNotification(ScreenChanged, view)` when modal UI appears or dismisses. Without these notifications, VoiceOver doesn't know to shift focus, leaving users navigating background controls instead of the picker popup. **Fix:** - Adds `PostAccessibilityFocusNotification()` extension methods in `SemanticExtensions.cs` - Posts `ScreenChanged` notification when picker popups open (in `EditingDidBegin` event) - Posts `ScreenChanged` notification to restore focus when popups close (in `EditingDidEnd` event) - Handles edge cases: null window checks, main thread dispatch for delayed InputView availability **Tests:** UI tests created in `Issue30746.xaml[.cs]` and marked with `ManualReview` category since VoiceOver focus cannot be automated with Appium. Manual testing with VoiceOver enabled confirms proper focus behavior. ### Issues Fixed Fixes #30746
…r popups (#33152) <!-- 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! ### Description of Change This PR fixes VoiceOver accessibility on iOS for Picker, DatePicker, and TimePicker controls. When picker popups open/close, VoiceOver now properly shifts focus using iOS accessibility notifications. **Root cause:** VoiceOver on iOS requires explicit focus notifications via `UIAccessibility.PostNotification(ScreenChanged, view)` when modal UI appears or dismisses. Without these notifications, VoiceOver doesn't know to shift focus, leaving users navigating background controls instead of the picker popup. **Fix:** - Adds `PostAccessibilityFocusNotification()` extension methods in `SemanticExtensions.cs` - Posts `ScreenChanged` notification when picker popups open (in `EditingDidBegin` event) - Posts `ScreenChanged` notification to restore focus when popups close (in `EditingDidEnd` event) - Handles edge cases: null window checks, main thread dispatch for delayed InputView availability **Tests:** UI tests created in `Issue30746.xaml[.cs]` and marked with `ManualReview` category since VoiceOver focus cannot be automated with Appium. Manual testing with VoiceOver enabled confirms proper focus behavior. ### Issues Fixed Fixes #30746
…r popups (#33152) <!-- 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! ### Description of Change This PR fixes VoiceOver accessibility on iOS for Picker, DatePicker, and TimePicker controls. When picker popups open/close, VoiceOver now properly shifts focus using iOS accessibility notifications. **Root cause:** VoiceOver on iOS requires explicit focus notifications via `UIAccessibility.PostNotification(ScreenChanged, view)` when modal UI appears or dismisses. Without these notifications, VoiceOver doesn't know to shift focus, leaving users navigating background controls instead of the picker popup. **Fix:** - Adds `PostAccessibilityFocusNotification()` extension methods in `SemanticExtensions.cs` - Posts `ScreenChanged` notification when picker popups open (in `EditingDidBegin` event) - Posts `ScreenChanged` notification to restore focus when popups close (in `EditingDidEnd` event) - Handles edge cases: null window checks, main thread dispatch for delayed InputView availability **Tests:** UI tests created in `Issue30746.xaml[.cs]` and marked with `ManualReview` category since VoiceOver focus cannot be automated with Appium. Manual testing with VoiceOver enabled confirms proper focus behavior. ### Issues Fixed Fixes #30746
…r popups (#33152) <!-- 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! ### Description of Change This PR fixes VoiceOver accessibility on iOS for Picker, DatePicker, and TimePicker controls. When picker popups open/close, VoiceOver now properly shifts focus using iOS accessibility notifications. **Root cause:** VoiceOver on iOS requires explicit focus notifications via `UIAccessibility.PostNotification(ScreenChanged, view)` when modal UI appears or dismisses. Without these notifications, VoiceOver doesn't know to shift focus, leaving users navigating background controls instead of the picker popup. **Fix:** - Adds `PostAccessibilityFocusNotification()` extension methods in `SemanticExtensions.cs` - Posts `ScreenChanged` notification when picker popups open (in `EditingDidBegin` event) - Posts `ScreenChanged` notification to restore focus when popups close (in `EditingDidEnd` event) - Handles edge cases: null window checks, main thread dispatch for delayed InputView availability **Tests:** UI tests created in `Issue30746.xaml[.cs]` and marked with `ManualReview` category since VoiceOver focus cannot be automated with Appium. Manual testing with VoiceOver enabled confirms proper focus behavior. ### Issues Fixed Fixes #30746
…r popups (#33152) <!-- 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! ### Description of Change This PR fixes VoiceOver accessibility on iOS for Picker, DatePicker, and TimePicker controls. When picker popups open/close, VoiceOver now properly shifts focus using iOS accessibility notifications. **Root cause:** VoiceOver on iOS requires explicit focus notifications via `UIAccessibility.PostNotification(ScreenChanged, view)` when modal UI appears or dismisses. Without these notifications, VoiceOver doesn't know to shift focus, leaving users navigating background controls instead of the picker popup. **Fix:** - Adds `PostAccessibilityFocusNotification()` extension methods in `SemanticExtensions.cs` - Posts `ScreenChanged` notification when picker popups open (in `EditingDidBegin` event) - Posts `ScreenChanged` notification to restore focus when popups close (in `EditingDidEnd` event) - Handles edge cases: null window checks, main thread dispatch for delayed InputView availability **Tests:** UI tests created in `Issue30746.xaml[.cs]` and marked with `ManualReview` category since VoiceOver focus cannot be automated with Appium. Manual testing with VoiceOver enabled confirms proper focus behavior. ### Issues Fixed Fixes #30746
.NET MAUI inflight/candidate introduces significant improvements across all platforms with focus on quality, performance, and developer experience. This release includes 20 commits with various improvements, bug fixes, and enhancements. ## Blazor - Fix for BlazorWebView Back Navigation Issues on Android 13+ After Predictive Back Gesture Changes by @SuthiYuvaraj in #33213 <details> <summary>🔧 Fixes</summary> - [Back navigation different between .net 9 and .net 10 blazor hybrid](#32767) </details> ## CollectionView - [Android] Fix for CollectionView.EmptyView does not remeasure its height when the parent layout changes dynamically, causing incorrect sizing. by @BagavathiPerumal in #33559 <details> <summary>🔧 Fixes</summary> - [`CollectionView.EmptyView` does not remeasure its height when the parent layout changes dynamically, causing incorrect sizing.](#33324) </details> - [Android] Fixed CollectionView reordering last item by @vitalii-vov in #17825 <details> <summary>🔧 Fixes</summary> - [Android app crashes when dragging into CollectionView](#17823) </details> ## DateTimePicker - [iOS] Fix VoiceOver focus not shifting to Picker/DatePicker/TimePicker popups by @kubaflo in #33152 <details> <summary>🔧 Fixes</summary> - [Voiceover does not automatically shift focus to the "Category" popup when it opens.: A11y_Developer balance version .NET 10_Project_ScreenReader](#30746) </details> ## Dialogalert - [iOS 26] Fix DisplayPromptAsync maxLength not enforced due to new multi-range delegate by @Shalini-Ashokan in #33616 <details> <summary>🔧 Fixes</summary> - [[iOS 26.1] DisplayPromptAsync ignores maxLength and does not respect RTL FlowDirection](#33549) </details> ## Flyout - [iOS] Shell: Account for SafeArea when positioning flyout footer by @kubaflo in #32891 <details> <summary>🔧 Fixes</summary> - [[IOS] Footer not displaying in iOS when StackOrientation.Horizontal is set on FlyoutFooter](#26395) </details> ## Fonts - Hide obsolete FontSize values from IDE autocomplete by @noiseonwires in #33694 ## Gestures - Android pan fixes by @BurningLights in #21547 <details> <summary>🔧 Fixes</summary> - [Flickering occurs while updating the width of ContentView through PanGestureRecognizer.](#20772) </details> ## Navigation - Shell: Add duplicate route validation for sibling elements by @SubhikshaSf4851 in #32296 <details> <summary>🔧 Fixes</summary> - [OnNavigatedTo is not called when navigating from a specific page](#14000) </details> ## Picker - Improved Unfocus support for Picker on Mac Catalyst by @kubaflo in #33127 <details> <summary>🔧 Fixes</summary> - [When using voiceover unable to access expanded list of project combo box: A11y_.NET maui_user can creat a tak_Screen reader](#30897) - [Task and Project controls are not accessible with keyboard:A11y_.NET maui_User can create a new task_Keyboard](#30891) </details> ## SafeArea - [iOS] SafeArea: Return Empty for non-ISafeAreaView views (opt-in model) by @praveenkumarkarunanithi in #33526 <details> <summary>🔧 Fixes</summary> - [[iOS] SafeArea is not applied when a ContentPage uses a ControlTemplate](#33458) </details> ## Shell - [iOS] Fix ObjectDisposedException in TraitCollectionDidChange on window disposal by @jeremy-visionaid in #33353 <details> <summary>🔧 Fixes</summary> - [Intermittent crash on exit on MacCatalyst - ObjectDisposedException](#33352) </details> - [Issue-Resolver] Explicit fallback for BackButtonBehavior lookup by @kubaflo in #33204 <details> <summary>🔧 Fixes</summary> - [Setting BackButtonBehavior to not visible or not enabled does not work](#28570) - [BackButtonBehavior not bound](#33139) </details> ## Templates - [Templates] Remove redundant SemanticProperties.Description attribute by @kubaflo in #33621 <details> <summary>🔧 Fixes</summary> - [Task and Project controls are not accessible with keyboard:A11y_.NET maui_User can create a new task_Keyboard](#30891) - [Unable to select "Tags" when Voiceover is turned on.: A11y_Developer balance version .NET 10_Project_ScreenReader](#30749) </details> ## Theme - [Windows] Fix runtime theme update for controls and TitleBar by @Tamilarasan-Paranthaman in #31714 <details> <summary>🔧 Fixes</summary> - [[Windows][MacOS?] Change title bar color when switching light/dark theme at runtime](#12507) - [OS system components ignore app theme](#22058) - [[Mac Catalyst][Windows] TitleBar not reacting on UserAppTheme changes](#30518) - [In dark theme "Back" and "hamburger" button icon color contrast with background color is less than 3:1: A11y_.NET maui_User can get all the insights of Dashboard_Non text Contrast](#30807) - [`Switch` is invisible on `PointOver` when theme has changed](#31819) </details> ## Theming - [XSG] Fix Style Setters referencing source-generated bindable properties by @simonrozsival in #33562 ## Titlebar - [Windows] Fix TitleBar.IsVisible = false the caption buttons become unresponsive by @devanathan-vaithiyanathan in #33256 <details> <summary>🔧 Fixes</summary> - [When TitleBar.IsVisible = false the caption buttons become unresponsive on Windows](#33171) </details> ## WebView - Fix WebView JavaScript string escaping for backslashes and quotes by @StephaneDelcroix in #33726 ## Xaml - [XSG] Fix NaN value in XAML generating invalid code by @StephaneDelcroix in #33533 <details> <summary>🔧 Fixes</summary> - [[XSG] NaN value in XAML generates invalid code](#33532) </details> <details> <summary>📦 Other (1)</summary> - Remove InternalsVisibleTo attributes for .NET MAUI Community Toolkit by @jfversluis via @Copilot in #33442 </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!
Description of Change
This PR fixes VoiceOver accessibility on iOS for Picker, DatePicker, and TimePicker controls. When picker popups open/close, VoiceOver now properly shifts focus using iOS accessibility notifications.
Root cause: VoiceOver on iOS requires explicit focus notifications via
UIAccessibility.PostNotification(ScreenChanged, view)when modal UI appears or dismisses. Without these notifications, VoiceOver doesn't know to shift focus, leaving users navigating background controls instead of the picker popup.Fix:
PostAccessibilityFocusNotification()extension methods inSemanticExtensions.csScreenChangednotification when picker popups open (inEditingDidBeginevent)ScreenChangednotification to restore focus when popups close (inEditingDidEndevent)Tests: UI tests created in
Issue30746.xaml[.cs]and marked withManualReviewcategory since VoiceOver focus cannot be automated with Appium. Manual testing with VoiceOver enabled confirms proper focus behavior.Issues Fixed
Fixes #30746