From 7ff3b37836df02bfc094c1fff2f5e716b051b421 Mon Sep 17 00:00:00 2001 From: Peter Abbondanzo Date: Mon, 16 Jun 2025 07:06:04 -0700 Subject: [PATCH] Mark hasTVPreferredFocus as deprecated Summary: The `hasTVPreferredFocus` prop is functionally similar to the `focusable` prop. On iOS, the props are identical. The primary difference appears on Android, where the prop attempts to request focus when set to true. Attempting to invoke imperative API calls through declarative means has been [a source of confusion](https://github.com/react-native-tvos/react-native-tvos/issues/237) and we should instead recommend requesting focus through imperative means, like calling `focus()` on a specific view's ref instead. Workarounds presented rely on lifecycle methods to request focus natively. This change only marks these methods as deprecated on JS. In the following version, they will be removed from the public API. Changelog: [General][Deprecated] - Deprecate `hasTVPreferredFocus` Differential Revision: D76732539 --- packages/react-native/Libraries/Components/Button.js | 1 + .../Libraries/Components/Touchable/TouchableHighlight.js | 3 +++ .../Libraries/Components/Touchable/TouchableNativeFeedback.js | 1 + .../Libraries/Components/Touchable/TouchableOpacity.d.ts | 1 + .../Libraries/Components/Touchable/TouchableOpacity.js | 1 + .../react-native/Libraries/Components/View/ViewPropTypes.d.ts | 4 ++++ .../react-native/Libraries/Components/View/ViewPropTypes.js | 1 + 7 files changed, 12 insertions(+) diff --git a/packages/react-native/Libraries/Components/Button.js b/packages/react-native/Libraries/Components/Button.js index 7824947d7617c1..2b944380e1f49d 100644 --- a/packages/react-native/Libraries/Components/Button.js +++ b/packages/react-native/Libraries/Components/Button.js @@ -63,6 +63,7 @@ export type ButtonProps = $ReadOnly<{ @platform tv @default false + @deprecated Use `focusable` instead */ hasTVPreferredFocus?: ?boolean, diff --git a/packages/react-native/Libraries/Components/Touchable/TouchableHighlight.js b/packages/react-native/Libraries/Components/Touchable/TouchableHighlight.js index 6d81eead72ba7b..338d6c99744ebb 100644 --- a/packages/react-native/Libraries/Components/Touchable/TouchableHighlight.js +++ b/packages/react-native/Libraries/Components/Touchable/TouchableHighlight.js @@ -30,6 +30,9 @@ type AndroidProps = $ReadOnly<{ }>; type IOSProps = $ReadOnly<{ + /** + * @deprecated Use `focusable` instead + */ hasTVPreferredFocus?: ?boolean, }>; diff --git a/packages/react-native/Libraries/Components/Touchable/TouchableNativeFeedback.js b/packages/react-native/Libraries/Components/Touchable/TouchableNativeFeedback.js index 4de3b0c790bd41..481c9adf2578d2 100644 --- a/packages/react-native/Libraries/Components/Touchable/TouchableNativeFeedback.js +++ b/packages/react-native/Libraries/Components/Touchable/TouchableNativeFeedback.js @@ -29,6 +29,7 @@ type TVProps = { * *(Apple TV only)* TV preferred focus (see documentation for the View component). * * @platform ios + * @deprecated Use `focusable` instead */ hasTVPreferredFocus?: ?boolean, diff --git a/packages/react-native/Libraries/Components/Touchable/TouchableOpacity.d.ts b/packages/react-native/Libraries/Components/Touchable/TouchableOpacity.d.ts index bd72669a22c4a0..d579a8d66b126c 100644 --- a/packages/react-native/Libraries/Components/Touchable/TouchableOpacity.d.ts +++ b/packages/react-native/Libraries/Components/Touchable/TouchableOpacity.d.ts @@ -16,6 +16,7 @@ export interface TVProps { * *(Apple TV only)* TV preferred focus (see documentation for the View component). * * @platform ios + * @deprecated Use `focusable` instead */ hasTVPreferredFocus?: boolean | undefined; diff --git a/packages/react-native/Libraries/Components/Touchable/TouchableOpacity.js b/packages/react-native/Libraries/Components/Touchable/TouchableOpacity.js index 8bba7ab14676ad..d2db6e3b918ff1 100644 --- a/packages/react-native/Libraries/Components/Touchable/TouchableOpacity.js +++ b/packages/react-native/Libraries/Components/Touchable/TouchableOpacity.js @@ -26,6 +26,7 @@ export type TVProps = $ReadOnly<{ * *(Apple TV only)* TV preferred focus (see documentation for the View component). * * @platform ios + * @deprecated Use `focusable` instead */ hasTVPreferredFocus?: ?boolean, diff --git a/packages/react-native/Libraries/Components/View/ViewPropTypes.d.ts b/packages/react-native/Libraries/Components/View/ViewPropTypes.d.ts index b52feb743bee3a..62803cabce7ec3 100644 --- a/packages/react-native/Libraries/Components/View/ViewPropTypes.d.ts +++ b/packages/react-native/Libraries/Components/View/ViewPropTypes.d.ts @@ -21,6 +21,9 @@ import { import {Touchable} from '../Touchable/Touchable'; import {AccessibilityProps} from './ViewAccessibility'; +/** + * @deprecated These properties are not implemented natively. + */ export interface TVViewPropsIOS { /** * *(Apple TV only)* When set to true, this view will be focusable @@ -34,6 +37,7 @@ export interface TVViewPropsIOS { * *(Apple TV only)* May be set to true to force the Apple TV focus engine to move focus to this view. * * @platform ios + * @deprecated Use `focusable` instead */ hasTVPreferredFocus?: boolean | undefined; diff --git a/packages/react-native/Libraries/Components/View/ViewPropTypes.js b/packages/react-native/Libraries/Components/View/ViewPropTypes.js index 2347f4f31bb1ed..a5b02b221663ca 100644 --- a/packages/react-native/Libraries/Components/View/ViewPropTypes.js +++ b/packages/react-native/Libraries/Components/View/ViewPropTypes.js @@ -280,6 +280,7 @@ export type ViewPropsAndroid = $ReadOnly<{ * Whether to force the Android TV focus engine to move focus to this view. * * @platform android + * @deprecated Use `focusable` instead */ hasTVPreferredFocus?: ?boolean,