A Guide to Handling Focus in Apple TV Apps with SwiftUI

01 / Sep / 2025 by Mukul Sharma 0 comments

Introduction

In Apple TV, the centre of user interaction is the focus engine. Apple TV does not use the touchscreen like iPhones and iPads, where one taps everything directly on the screen, but uses the remote control to navigate among the elements. This is to say that the usability of your app largely relies on the ease and predictability with which the focus between one view and another transitions. Without good management of focus, users can become lost, frustrated or stuck on a screen. However, when done right, focus management causes your application to feel natural, responsive, and pleasant to use.

SwiftUI has now gained more focus management capabilities, such as focusable, focus state, and custom focus guides, as well as better navigation control. Be it a settings screen, a media carousel, or a content grid, focus behavior is a key aspect to master to create a smooth and engaging user experience on tvOS.

In this blog, we’ll explore:

  • What is the focus engine and how does it work.
  • Learning to make elements focusable in SwiftUI.
  • Managing programmatic focus with @FocusState
  • Handling complex layouts like carousels and grids.

By the end, you will know how to create hassle-free and user-friendly Apple TV apps that users will touch and feel as they navigate with the remote controller.

Let’s begin with fundamentals:

1. Enabling an element to be focusable:

You can make a view focusable in SwiftUI for tvOS using the focusable() modifier. Here’s an easy example to know how it works.

focusableImage

focusableImage

2. Switch focus between two buttons:

To control our focus between buttons, we bought to remember which button we are focused on and update the UI to indicate the same. This is implemented with SwiftUI with the FocusState.

Steps to handle focus:

  1. Define focusable field: Create an enum FocusField (e.g., .button1, .button2) to represent the focusable buttons.
  2. Track the focused element: Use @FocusState var focusedField: FocusField? to keep track of the currently focused button.
  3. Change focus of buttons:  use .focused($focusedField, equals: .button1).
  4. Update UI based on focus: Yellow if focused and Gray if not focused.
  5. Set initial focus: In .onAppear, set the default focus.

A simple example to demonstrate how it works

defaultFocusbutton

defaultFocusbutton

focusButton

focusButton

By using .focused($focusedField, equals: .button1), we are able to set and follow the current focus. To dynamically change the color of text when focused, we check the current focusedField value and set an alternate color when the element has focus.

3. Manually Moving Focus to a Specific Element When Alignment Breaks:

In SwiftUI for tvOS, when handling this scenario, we can use onMoveCommand to implement custom focus navigation. Let’s look at some sample code to see how we can move focus between elements.

  • As we have pressesBegan in UIKit, similarly in SwiftUI, we have “customFocusNavigation” to get the direction of the remote from the current focus element.
  • So, according to the direction we get from the onMoveCommand, we can set our custom focus.

A simple example to demonstrate how it works

un-alignButton

un-alignButton

The above image shows two buttons placed unevenly on the left and right sides of the screen. In such cases, the default focus engine may not provide smooth navigation between them.

customFocusNavigation

customFocusNavigation

  •  OnMoveCommand assists us in creating personalized up/down navigation such that when we press the arrows of the remote, we travel focus according to our preference.
  •  In such a way, although the alignment of UI elements might not match, we can still control the flow of focus manually and offer a smooth experience of the navigation.

Conclusion

The essence of a great tvOS is focus management. Although the default Focus Engine is sufficient to handle most scenarios, asynchronously placed elements may have to be handled with specialized control. Using both onMoveCommand and @FocusState, we can take control of the flow of navigation such that a user is always returned to the right element with an animative flow that is both seamless and predictable. But not only is it more usable, but it also gives us a good interface to the apps on the tvOS.

FOUND THIS USEFUL? SHARE IT

Leave a Reply

Your email address will not be published. Required fields are marked *