Skip to content

Add navigationStrategy to override default behavior#231

Draft
xavi160 wants to merge 1 commit intonextfrom
navigation-strategy
Draft

Add navigationStrategy to override default behavior#231
xavi160 wants to merge 1 commit intonextfrom
navigation-strategy

Conversation

@xavi160
Copy link
Copy Markdown
Collaborator

@xavi160 xavi160 commented Apr 27, 2026

Summary

Adds an optional navigationStrategy hook so a parent focus scope can override default spatial navigation when moving between siblings. When set on the parent focusable, arrow navigation among its children uses your function instead of cutoff coordinates and priority sorting.

Motivation

Default spatial navigation is geometry-based (cutoff coordinates, RTL/LTR, sortSiblingsByPriority). Some UIs need deterministic or domain-specific ordering (e.g. custom grids, masked lists, non-rect layouts, overlapped elements...). This change lets callers supply the next focus target explicitly while keeping the existing algorithm as the default when no strategy is provided.

API

  • Type NavigationStrategy:
    (
      direction: Direction,
      focusKey: string,
      siblings: FocusableComponent[]
    ) => FocusableComponent | null

FocusableComponent.navigationStrategy (optional) — stored and updated with addFocusable / updateFocusable.
useFocusable({ navigationStrategy }) — passes the strategy through registration and dependency updates.

Behavior

During smartNavigate, the service reads navigationStrategy from the parent (focusableComponents[parentFocusKey]).
If present: collects siblings with the same parentFocusKey that are focusable, calls navigationStrategy(direction, focusKey, siblings), and uses its return value as the next component (skips default sibling filtering by layout cutoff, visual-debug sibling drawing for that path, and sortSiblingsByPriority).

…NavigationService for custom navigation handling
@xavi160 xavi160 self-assigned this Apr 27, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 27, 2026

🦋 Changeset detected

Latest commit: e17ccdb

The changes in this PR will be included in the next version bump.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@xavi160 xavi160 changed the base branch from main to next April 27, 2026 10:52
siblings.map((sibling) => sibling.focusKey).join(', '),
siblings.map((sibling) => sibling.node),
siblings.map((sibling) => sibling)
nextComponent = navigationStrategy(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is external function, we should add some warnings if the returned nextComponent is invalid/missing/not in focusable components list, so people see that their navigationStrategy is not working as intended.

focusBoundaryDirections?: Direction[];
autoRestoreFocus: boolean;
forceFocus: boolean;
navigationStrategy?: NavigationStrategy;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

navigationStrategy name is misleading, this is a function, while the name suggests it's an object

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I know, I wanted to avoid navigationStrategyFn or similar. Not sure if onNavigate is a good one either

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Naming is hard 😆

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getNextNavigationTarget, onNavigateToCustom, onIncerceptNavigation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants