Repository navigation
Conversation
On iOS, the traits derived from the role and `accessibilityState` are written onto the inner `UISwitch` and replace UIKit's own `NotEnabled` trait. The iOS branch of `Switch.js` never folded `disabled` into `accessibilityState`, so a disabled Switch was reported as enabled to VoiceOver and XCUITest. Share the Android branch's existing logic with iOS.
|
Hi @arun279! Thank you for your pull request and welcome to our community. Action RequiredIn order to merge any pull request (code, docs, etc.), we require contributors to sign our Contributor License Agreement, and we don't seem to have one on file for you. ProcessIn order for us to review and merge your suggested changes, please sign at https://code.facebook.com/cla. If you are contributing on behalf of someone else (eg your employer), the individual CLA may not be sufficient and your employer may need to sign the corporate CLA. Once the CLA is signed, our tooling will perform checks and validations. Afterwards, the pull request will be tagged with If you have received this in error or have any questions, please contact us at cla@meta.com. Thanks! |
|
Thank you for signing our Contributor License Agreement. We can now accept your code for this (and any) Meta Open Source project. Thanks! |
| ref?: React.RefSetter<SwitchInstance>, | ||
| ...SwitchProps, | ||
| }): React.Node { | ||
| const { |
There was a problem hiding this comment.
Extract accessibilityState here.
Summary:
On iOS,
<Switch disabled />is drawn greyed out and ignores taps, but VoiceOver and XCUITest still report it as enabled: theUIAccessibilityTraitNotEnabledtrait is missing.Since #50796, the inner
UISwitchis the Switch's accessibility element, soRCTViewComponentViewwrites the traits it derives from the role onto theUISwitch, replacing the ones UIKit sets, includingNotEnabled. Since #57516,accessibilityState.disabledaddsNotEnabledto those traits, but the iOS branch ofSwitch.jsnever sets it fromdisabled. The Android branch already does.This moves the existing Android logic above the platform check so iOS gets the same
accessibilityState. As on Android,disabledwins overaccessibilityState.disabledwhen both are set. It is done inSwitch.jsrather thanRCTSwitchComponentViewbecause the Android branch already does it here, and a Switch-specific native writer for the traits would bring back the second trait writer that #57516 removed.disablednow behaves exactly likeaccessibilityState={{disabled: true}}already does. That includes a Switch whose role maps to no trait, such asaccessibilityRole="none": it getsNotEnabledalone, without the switch trait.Changelog:
[IOS] [FIXED] - Report a disabled
Switchas disabled to VoiceOver and XCUITestTest Plan:
Added
Switch-test.js. Jest renders the iOS branch, whileSwitch-itest.js(Fantom) renders the Android one. Two of its three cases fail without this change.Manual check: a new 0.88.0 app (prebuilt core;
Switch.jsis the same on 0.88.0 andmain) on an iPhone 17 Pro simulator, iOS 27. For "After", this branch'sSwitch.jswas copied into the app'snode_modules/react-native/Libraries/Components/Switch/. The accessibility tree was read with AXedescribe-ui, which reports each element'senabledattribute.disabled-mountdisabled-live, afterdisabledis set totruedisabled-live, afterdisabledis set back tofalsedisabled-stateThe role (
switch) and value (1) are unchanged.Not run locally:
Switch-itest.js, which needs the Fantom native tester build. CI's Fantom job runs it, and the Android branch only had its existing logic moved. Also not run: VoiceOver on a device.