forked from facebook/react-native
-
Couldn't load subscription status.
- Fork 149
Refactor how focusable is handled in RCTView
#1437
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Conversation
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
amgleitman
approved these changes
Sep 21, 2022
|
Tabling this for a bit while I explore an alternate fix. |
mischreiber
approved these changes
Sep 27, 2022
focusable to not depend on [NSApp isFullKeyboardAccessEnabled]focusable is handled in RCTView on macPS
focusable is handled in RCTView on macPSfocusable is handled in RCTView on macOS
focusable is handled in RCTView on macOSfocusable is handled in RCTView
chiuam
approved these changes
Oct 26, 2022
mischreiber
reviewed
Oct 26, 2022
mischreiber
approved these changes
Oct 26, 2022
Saadnajmi
added a commit
that referenced
this pull request
Sep 19, 2025
Needs #2690 to land first. ## Summary: Implement focus on RCTViewComponentView. Much of the implementation is taken from #1437, #2117 and comparing against `RCTView`. The border path used for `drawFocusRingMask` is the same as what is used for box shadows and cursors. ## Test Plan: The focus loop seems nonexistent on both paper and Fabric in RNTester... but I can verify that calling `ref.current?/.focus()` on a Pressable displays the focus ring
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.
Please select one of the following
Summary
This PR does slight refactoring on how the
focusableprop is handled by React Native macOS.[RCTView acceptsFirstResponder]now doesn't depend on[NSApp isFullKeyboardAccessEnabled], and only depends on the propfocusable.We initially only accepted first responder status if both focusable and
[NSApp isFullKeyboardAccessEnabled]were true to properly respect a specific system preference, and only make<View focusable>into a key view (AKA: tab stop) if the user allowed it. However, that's actually the wrong method to override, NSView's canBecomeKeyView is.Looking at some old Apple docs:
It seems that the default implementation of
[NSView canBecomeKeyView]will check that OS preference for us, so we can do less work :).Discussion
This work is done to unblock a bug in FluentUI React Native, where we want our custom NSMenu Replacement always take keyboard focus, regardless of the OS preference (menus are a special case that shouldn't respect that OS preference).
Natively in Appkit, there are two relevant NSView methods that control keyboard focus:
acceptsFirstResponderand `canBecomeKeyView.[NSView acceptsFirstResponder]: controls whether a view can receive focus at all (programmatically, via the key view loop, etc).[NSView canBecomeKeyView]: controls whether a view can receive focus from the key view loop (AKA: Can you press tab to get focus on the view, AKA: Is it a tab stop).[NSApp isFullKeyboardAccessEnabled]: System preference that determines how many controls get keyboard focus. By default it's turned off, so most native Appkit views do not get keyboard focus. See https://microsoft.github.io/apple-ux-guide/KeyboardFocus.html .In React Native, the View prop
focusableis a cross platform prop that determines whether a View receives keyboard focus. We implemented it natively by havingacceptsFirstResponder(AKA, can a View receive focus at all) only return true if bothfocusableis true and[NSApp isFullKeyboardAccessEnabled]is true. This behavior approximately matches the equivalent SwiftUI Modifier.However, this leaves JS developers at an impasse. There is no way in JS for a developer to "force" a view to always be focusable. I needed this for my custom NSMenu replacement. To further complicate matters, Apple has confusingly introduced a new, similarly named system accessibility preference Full Keyboard Access that allows the user to force every view to be keyboard focusable. This new preference is on both iOS and macOS and seems to use an entirely different keyboard focus ring / OS layer / whatever you want to call it. So it feels like Apple might have forgotten about the original preference
[NSApp isFullKeyboardAccessEnabled]? Or at least, would rather you forgot about it and use their new system preference?Last weird bit... I also needed to override
[NSView needsPanelToBecomeKey]so that clicking on a<View focusable> / <Touchable> / <Pressable>wouldn't place keyboard focus on it. That was quite jarring, and doesn't match what anNSControllikeNSButtondoes natively. For more info, see https://stackoverflow.com/questions/55078226/first-responder-on-mouse-down-behavior-nscontrol-and-nsviewWhile this change doesn't make it easier for JS developers to force a view to always be focusable, it does unblock a native module like FocusZone to force focus. It's not perfect, but I think it's a better state than we were before :).
Changelog
[macOS] [Fixed] - Refactor how
focusableis handled natively on macOSTest Plan
Tested the View test page in RNTester. Notice that when the preference is OFF, only the TextField can receive focus (as it should be).
Screen.Recording.2022-10-25.at.3.30.06.PM.mov