TVFocusGuide
TVFocusGuide helps you to write intuitive TV apps, by supporting autofocus. This feature finds or recovers the focus and remembers the focus on multiple visits. TVFocusGuide also supports trapping and focus redirection, allowing you to customize the focus behavior in your app.
This component makes sure that focusable controls can be navigated to, even if they are not directly in line with other controls. An example in RNTester shows two different ways of using this component.
| Prop | Value | Description |
|---|---|---|
| destinations | any[]? | Array of Components to register as destinations of the FocusGuideView |
| autoFocus | boolean? | If true, TVFocusGuide manages focus for you. Redirects the focus to the first focusable child on the first visit. Remembers the last focused child and redirects the focus to it on the subsequent visits. The destinations prop takes precedence over this prop when used together. |
| trapFocus* (Up, Down, Left, Right) | Prevents focus escaping from the container for the given directions. |
The following animation shows navigating controls when using TVFocusGuideView.

For more information on the focus handling improvements, see Revolutionizing Focus Management in TV Applications with React Native.
Example
import React from 'react';
import {
Dimensions,
View,
StyleSheet,
TouchableHighlight,
Text
} from 'react-native';
import {
TVFocusGuideView
} from '@amazon-devices/react-native-kepler';
const screenHeight = Dimensions.get('window').height;
const scale = screenHeight / 1080;
const width = 200 * scale;
const height = 120 * scale;
const theme = {
LinkColor: '#0984ffff',
LabelColor: '#ffffffff',
TertiarySystemFillColor: '#3085C3',
BackgroundColor: '#0c0700ff'
};
const Button = React.forwardRef((props: $FlowFixMeProps, ref) => {
const [focused, setFocused] = React.useState(false);
return (
<TouchableHighlight
onPress={() => {
if (props.onPress) {
props.onPress();
}
console.log(`${props.label} in press`);
}}
onFocus={() => {
if (props.onFocus) {
props.onFocus();
}
console.log(`${props.label} in focus`);
setFocused(true);
}}
onBlur={() => {
if (props.onBlur) {
props.onBlur();
}
console.log(`${props.label} in blur`);
setFocused(false);
}}
style={focused ? styles.buttonStyleFocused : styles.buttonStyle}
ref={ref}>
<Text style={[{ color: theme.LinkColor }, styles.buttonText]}>
{props.label}
</Text>
</TouchableHighlight>
);
});
const ThemedView = (props: $FlowFixMeProps) => {
return (
<View style={[styles.buttonStyle, props.style]}>
<Text style={[{ color: theme.LabelColor }, styles.buttonText]}>
{props.label}
</Text>
</View>
);
};
const TVFocusGuideExample = () => {
const [destination, setDestination] = React.useState(null);
const [destinationText, setDestinationText] = React.useState('');
const destinations = destination?.current ? [destination?.current] : [];
const buttonTopRight = React.useRef(null);
const buttonBottomLeft = React.useRef(null);
const rightButtonInFocusViewContainer = React.useRef(null);
const containerDestinations = rightButtonInFocusViewContainer?.current
? [rightButtonInFocusViewContainer?.current]
: [];
const _setDestination = (o: Object, text: string) => {
setDestination(o);
setDestinationText(text);
};
return (
<View
style={[styles.container, { backgroundColor: theme.BackgroundColor }]}>
<View style={styles.rowContainer}>
<Button onPress={() => {}} label="Left Top" />
<Button
onPress={() => {}}
onFocus={() => _setDestination(buttonBottomLeft, 'bottom left')}
ref={buttonTopRight}
label="Right Top"
/>
<ThemedView label={`Focus guide points to ${destinationText}`} />
{/* @ts-expect-error */}
<TVFocusGuideView
style={styles.containerFocusGuide}
destinations={containerDestinations}>
<Button onPress={() => {}} label="Wrapped button 1" />
<Button onPress={() => {}} label="Wrapped button 2" />
<Button
ref={rightButtonInFocusViewContainer}
onPress={() => {}}
label="Wrapped button 3"
/>
</TVFocusGuideView>
</View>
<View style={styles.rowContainer}>
<Button
onPress={() => {}}
onFocus={() => _setDestination(buttonTopRight, 'top right')}
ref={buttonBottomLeft}
label="Left Bottom"
/>
<TVFocusGuideView
style={[
{ backgroundColor: theme.TertiarySystemFillColor },
styles.focusGuide
]}
destinations={destinations}>
<Text style={[{ color: theme.LabelColor }, styles.buttonText]}>
Focus guide
</Text>
</TVFocusGuideView>
<ThemedView label="" />
<ThemedView
style={{
width: width * 3
}}
label="Blue focus guide container above always points to button 3
if navigating from the outside"
/>
</View>
</View>
);
};
const marginSize = 20 * scale;
const styles = StyleSheet.create({
container: {
marginTop: -marginSize,
height: screenHeight
},
rowContainer: {
flexDirection: 'row',
padding: 100 * scale
},
buttonText: {
fontSize: 30 * scale
},
buttonStyle: {
width,
height,
marginLeft: marginSize,
marginRight: marginSize,
marginTop: marginSize,
marginBottom: marginSize
},
buttonStyleFocused: {
opacity: 0.5,
borderColor: 'white',
borderWidth: 4,
width,
height,
marginLeft: marginSize,
marginRight: marginSize,
marginTop: marginSize,
marginBottom: marginSize
},
focusGuide: {
width,
height,
marginLeft: marginSize,
marginRight: marginSize,
marginTop: marginSize,
marginBottom: marginSize
},
containerFocusGuide: {
backgroundColor: 'transparent',
borderColor: 'blue',
borderWidth: 2,
flexDirection: 'row'
}
});
export default TVFocusGuideExample;
Reference
Props
autoFocus
If true, TVFocusGuide manages the focus for you. TVFocusGuide redirects the focus to the first focusable child on the first visit. This prop also remembers the last focused child and redirects the focus to it on the subsequent visits. The destinations prop takes precedence over this prop when used.
| Type | Required |
|---|---|
| boolean | No |
trapFocus* (Up, Down, Left, Right)
Prevents focus escaping from the container for the given directions.
| Type | Required |
|---|---|
| boolean | No |
destinations
Array of components to register as destinations of the FocusGuideView.
| Type | Required |
|---|---|
| array of references | No |
Methods
setDestinations
setDestinations([ref1, ref2, ...]);
Array of Components to register as destinations of the FocusGuideView.
| Type | Required |
|---|---|
| array of references | No |
Known issues
- If
setDestinationsisn't mounted, the callback fails to update. Either use thedestinationsprop instead or add a delay usingsetTimeoutbefore callingsetDestinations. TVFocusGuidefails withProperty children does not exist on typewhen imported in .tsx with strict type checking. Apps can add{/* @ts-expect-error */}or{/* @ts-ignore */}before using a component to avoid the error.
const TVApp = () => {
return (
<View>
{/* @ts-expect-error */}
<TVFocusGuideView>
<Text>Hello World</Text>
</TVFocusGuideView>
</View>
);
};
Additional Resources
For information on other libraries, see Supported Third-Party Libraries and Services.
Last updated: Sep 30, 2025

