as

Settings
Sign out
Notifications
Alexa
Amazon Appstore
Ring
AWS
Documentation
Support
Contact Us
My Cases
Get Started
Design and Develop
Publish
Reference
Support

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.

Animated GIF that shows several sections of a screen and how the focus changes from one to the other. Some text instruction says, Focus guide points to bottom left. Another instruction says, Blue focus guide container above always points to button 3 if navigating from outside.

For more information on the focus handling improvements, see Revolutionizing Focus Management in TV Applications with React Native.

Example

Copied to clipboard.


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

Copied to clipboard.


setDestinations([ref1, ref2, ...]);

Array of Components to register as destinations of the FocusGuideView.

Type Required
array of references No

Known issues

  • If setDestinations isn't mounted, the callback fails to update. Either use the destinations prop instead or add a delay using setTimeout before calling setDestinations.
  • TVFocusGuide fails with Property children does not exist on type when imported in .tsx with strict type checking. Apps can add {/* @ts-expect-error */} or {/* @ts-ignore */} before using a component to avoid the error.

Copied to clipboard.


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