useFocusable
Registers a component instance with the nearest FocusBoundary
import { useFocusable } from "@roku-sdk/navigation";useFocusable(options: UseFocusableOptions): UseFocusableResultDescription
Registers a component instance with the nearest FocusBoundary.
Must be called inside a component rendered within a RootFocusBoundary or FocusBoundary. Registration (and the ordering of focusables for navigation) follows render order.
Parameters
| Name | Type | Description |
|---|---|---|
options | UseFocusableOptions | Options passed to useFocusable. Extends FocusHandlers with an optional pre-created focusId identity. |
Return values
The leaf's focus state and registration helpers. See UseFocusableResult.
Example
const { isFocused, ref } = useFocusable({
focusId: props.focusId,
onKey: {
[RemoteKey.Select]: press => {
if (press) props.onSelect?.();
}
}
} satisfies UseFocusableOptions);
return (
<group ref={ref} translation={[0, props.y]}>
<rectangle width={400} height={56} color={isFocused() ? "0x0055DDFF" : "0x222222FF"} />
<label text={props.label} color={isFocused() ? "0xFFFFFFFF" : "0xBBBBBBFF"} translation={[16, 14]} />
</group>
);Types
UseFocusableResult
Return value of useFocusable.
| Name | Type | Description |
|---|---|---|
focus | () => void | Imperatively move virtual focus to this component. |
focusId | FocusId | The stable identity object used by the focus system. Only needed when you let useFocusable auto-create the identity and need to pass it elsewhere programmatically. When you pre-create the identity via options.focusId, you already have it — focusId just mirrors it back. |
hasFootprint | () => boolean | Reactive accessor; true when this item is the remembered focus target but the boundary is inactive (SG focus is elsewhere). See below. |
hasReturnFootprint | () => boolean | See below. |
isFocused | () => boolean | Reactive accessor; use to drive visual focus state. |
ref | (el: unknown) => void | Ref callback to attach to the root JSX element. Always defined — captures the DomNode for RootFocusBoundary focus-path computation (no-op when the root boundary has no setFocusPath). |
UseFocusableResult.hasFootprint
Reactive accessor; true when this item is the remembered focus target but the boundary is inactive (SG focus is elsewhere). Use to render a dimmed focus indicator so the user knows where focus will land on return.
Evaluated against this boundary alone, so every inactive boundary marks its own remembered child — including regions focus will not return to, and regions with rememberLastFocus={false} that reopen at initialFocus. To mark only items focus will actually land on, use hasReturnFootprint.
UseFocusableResult.hasReturnFootprint
Reactive accessor; true when this item is where focus will land if its boundary becomes active again — the boundary is inactive, sits on the return path up to the nearest active ancestor, and this item is that boundary's return target (honouring rememberLastFocus / initialFocus; a root keeps its focused child, because focusActive does not reset). Unlike hasFootprint, an off-path nested region never marks an item.
Every dormant sibling region under the nearest active ancestor marks one item — the one focus lands on if the user moves into that region — so N sibling regions with focus in one of them show N - 1 footprints. Exactly one item is marked in the tree only when the root itself is inactive. For a marker around the whole region, use useFocusActions().hasReturnFootprint.
UseFocusableOptions
Options passed to useFocusable. Extends FocusHandlers with an optional pre-created focusId identity.
| Name | Type | Description |
|---|---|---|
focusId? | FocusId | A pre-created stable object to use as this component's virtual focus identity. See below. |
Extends FocusHandlers.
UseFocusableOptions.focusId
A pre-created stable object to use as this component's virtual focus identity. Use this when you need to pass the identity to FocusBoundary's initialFocus prop.
If omitted, useFocusable creates a new {} object automatically.
FocusHandlers
Handler interface that a focusable component can provide when calling useFocusable. All fields are optional.
| Name | Type | Description |
|---|---|---|
canReceiveFocus? | () => boolean | If provided, the boundary will only move virtual focus here when this returns true. Defaults to always focusable. |
onFocusGained? | () => void | Called when this component gains virtual focus. |
onFocusLost? | () => void | Called when this component loses virtual focus. |
onKey? | KeyHandlerMap | Declarative key handler map. See below. |
FocusHandlers.onKey
Declarative key handler map. Each key in the record is a remote key name that this component handles. The boundary derives handledKeys from Object.keys(onKey) and evaluates any when gates reactively.
Dispatch: when a key event arrives and the key exists in onKey, the handler is called directly. If the entry has a when gate that returns false at dispatch time, the handler is skipped and the key is treated as unhandled.
Updated about 4 hours ago