Repository navigation
Hide unshown validation messages from VoiceOver - #105
Merged
Merged
Conversation
Forms keep a validation message in the layout and make it invisible with a clear foreground color while the field is valid. A clear Text is still an accessibility element, so VoiceOver read errors that weren't there (e.g. "Name is required." under a filled-in name). Add validationMessage(isShown:), which applies the validation color or clear and hides the text from accessibility while it isn't shown, and use it at all 12 sites (sign-up, profile, password x2, shop create x2, shop basic settings x2, item tag create x2, item tag edit x2). ValidationMessageTest hosts the modifier in a UIHostingController with app accessibility enabled and walks the accessibility elements: the hidden message must be absent and the shown one present, with a visible sibling Text proving the walk reaches SwiftUI's elements. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YDK5huvuRECyVrsQEdTN9q
UIWindow(frame:) is deprecated in iOS 26 and warned in CI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YDK5huvuRECyVrsQEdTN9q
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Forms keep their validation message in the layout and make it invisible with
.foregroundStyle(... ? .validationError : .clear)while the field is valid. A clearTextis still an accessibility element, so VoiceOver reads an error that isn't there (e.g. "Name is required." under a filled-in name). The Android app had the same bug (found on a device 2026-10-16).Fix
New
validationMessage(isShown:)modifier (UI/Shared/ValidationMessage.swift): the validation color when shown, otherwise.clearplus.accessibilityHidden(true), so the layout stays stable. It is used at all 12 sites that hid a message this way:SignUpView(name)ShopkeeperEditView(name)PasswordEditView(current password, confirm password / mismatch)ShopCreateView(name, description)ShopBasicSettingsView(name, description)ItemTagCreateView(name, description)ItemTagEditView(name, description)The app target is not a synced group, so the new file is registered in
project.pbxproj(4 lines, nothing else).Test
ValidationMessageTesthostsVStack { Text(sibling); Text(message).validationMessage(isShown:) }in aUIHostingControllerin a window and walks the hosting view'saccessibilityElements. SwiftUI builds those elements only while accessibility is on, so the test turns it on for the process with_AXSApplicationAccessibilitySetEnabledfrom the system's libAccessibility (viadlsym; no new dependency) and back off afterwards. The visible sibling label is asserted too, which proves the walk reaches SwiftUI's elements. Without enabling accessibility, the walk found no elements at all..accessibilityHidden(!isShown)failshiddenMessageIsNotAnAccessibilityElement(the bug reproduced)..accessibilityHidden(true)failsshownMessageIsAnAccessibilityElement.make lintis clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01YDK5huvuRECyVrsQEdTN9q