Focus Management on You.i Engine One: Trapping Focus

John Cassidy
5 min readFeb 13, 2020

A Quick Recap on Scene Trees

When building an application that will ultimately be rendered by You.i Engine One, the JSX (Facebook Components or After Effects Compositions) that you create will ultimately be represented as a Scene Tree. This Scene Tree is a collection of nodes with relationships (parent-child-sibling) to each other that represent the structure of your application.

When constructing a Composition in After Effects, the relationships are defined by which compositions are nested in other compositions.

Basic AE example that demonstrates buttons nested within Compositions

You can even view these relationships within After Effects by viewing the Composition FlowChart.

A Composition FlowChart that shows the relationship between Compositions

If we were to create a rough Scene Tree example of the above, it would break down to something like the following:

When constructing a screen out of JSX, the relationships are defined again by which components are within other components. We could represent the above in Pure JSX with:

<View>
<Button />
<Button />
<View>
<Button />
<Button />
</View>
</View>

Default Focus Management

If we take our sample After Effects Composition from above and represent it in a You.i Engine One Application, in its simplest form we would load the composition like so:

This will load the composition as it is in its default state. Since we are not referencing any of the elements inside the composition, they are free to behave with their default behaviour. This includes default focus handling for any focusable elements within the view.

Before we take a look at what that default focus handling looks like, we can enable the Focus Debugger in the applications Debug Panel (Click 3 times on top left of macOS build, or press play 3 times on remote on tvOS / Android TV, or other Connected TV platform)

Enabling the Focus Debugger to visually show where focus can travel

Now that we have enabled the Focus Debugger, we can navigate within the application (as our sample Composition has focusable Buttons within it) and the next focusable element in each direction (up-down-left-right) can be seen.

As you can see, the default focus behaviour is to find the closest focusable element (with some rules and calculations in the engine) and go there. You can jump between sections of Scene Tree if needed, it simply allows you to navigate the application in the most free way possible.

Trapping Focus to Particular Parts of the Application

There are some situations in which you don’t want focus to be able to move anywhere. A fairly common example is if you display a modal dialog with an OK and CANCEL button. While the dialog only represents a small section of the scene tree, there are still other elements that are also focusable all around it. The default behaviour would allow you to focus elements behind the dialog, because it’s the path of least resistance to being able to move about your application.

The You.i Engine One Focus Manager provides some tools to customize this behaviour, the ones we care about in particular for this purpose are below:

Snipped version of FocusManager to show functions we care about to trap focus

The idea of a focus root is fairly simple:

If focus is obtained on a node marked as a focus root, or a descendant of a node marked as a focus root, focus will not be able to leave that sub-tree until the node marked as focus root is turned off, or focus is programmatically placed elsewhere outside of the sub-tree.

In other words, focus will be trapped in that sub-tree until we tell it not to be anymore. If we are to look at our above sample composition and mark the Container node as a focus root, if focus enters that sub-tree it will trap focus to the focusable elements within it (in this case ButtonC and ButtonD)

Setting Container to be a focus root will trap focus within the sub-tree

We can use the FocusManager provided by You.i Engine One to reference our scene tree elements and mark the appropriate node as a focus root.

The result is that when focus enters the sub-tree by focusing on ButtonC or ButtonD, it will be trapped becauseContainer was marked as a focus root. You can observe in the lower right corner that the focusable elements of ButtonC and ButtonD only refer to each other, they are blind to others outside of the focus root. (the gif below loops, but focus is trapped. The start of the loop is when focus is in the top left corner)

Trapping focus when descendants of a focus root are selected

If you wish to set a focus root and then force focus immediately to that sub-tree, you can do so by immediately requesting focus on the focus root (even if it itself is not focusable, it will find it’s closest child that is)

Where can this be used?

I use this strategy often when displaying modal dialogs where I want to keep the user trapped to a particular set of focusable elements (buttons or options). A modal dialog isn’t necessarily a full screen takeover, it can simply be UX where the user must select a particular toggle or press back to leave the engagement.

This can also be quite useful when navigating between screens. By immediately setting the new screen to be a focus root upon mount and requesting focus, you eliminate the chance of focus being obtained by the screen below on the navigation stack.

This is a nice generic API that provides a lot of power in controlling where users can navigate in their Connected TV application.

--

--