Skip to content

Focus system hardening: traversal, zones, traps, layers, and persistence#81

Merged
RtlZeroMemory merged 4 commits into
mainfrom
focus-system-hardening
Feb 18, 2026
Merged

Focus system hardening: traversal, zones, traps, layers, and persistence#81
RtlZeroMemory merged 4 commits into
mainfrom
focus-system-hardening

Conversation

@RtlZeroMemory

Copy link
Copy Markdown
Owner

Summary

  • hardens focus management behavior without adding new focus features
  • fixes zone traversal tie ordering to preserve tree/visual order when tabIndex ties
  • fixes TAB routing in mixed zone/non-zone trees so non-zoned focusables remain reachable
  • constrains trap initialFocus to IDs inside the trap with deterministic fallback
  • fixes dropdown Enter/Space activation when selectedIndex is non-selectable

Tests Added

  • packages/core/src/runtime/__tests__/focus.traversal.test.ts (31)
  • packages/core/src/runtime/__tests__/focus.zones.test.ts (33)
  • packages/core/src/runtime/__tests__/focus.traps.test.ts (18)
  • packages/core/src/runtime/__tests__/focus.layers.test.ts (23)
  • packages/core/src/runtime/__tests__/focus.persistence.test.ts (14)
  • total new deterministic tests: 119

Docs

  • updated docs/guide/input-and-focus.md with persistence rules, zone tie-ordering, and trap initialFocus fallback guidance

Validation

  • npm run lint
  • npm run build
  • npm run typecheck
  • node scripts/run-tests.mjs

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3d50a256c9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/core/src/runtime/focus.ts Outdated
if (firstInTrap !== undefined && focusSet.has(firstInTrap)) {
nextFocusedId = firstInTrap;
const trapFocusables = trap.focusableIds;
if (trapFocusables.length > 0) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Honor trap initialFocus when trap focusables list is empty

This new guard makes initialFocus unreachable whenever trap.focusableIds is empty, but traps can legitimately have an empty direct list when their focusable descendants are wrapped in nested containers (for example a focusZone, per widgetMeta’s innermost-container attribution). In that case, activating a trap with a valid initialFocus inside the trap no longer moves focus into the modal and leaves focus outside while the trap is active, which is a regression from the prior behavior where initialFocus could still be applied.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Addressed in 8afacab. initialFocus is now honored when a trap has an empty direct focusableIds list (e.g. nested focus containers), while still enforcing containment when direct trap focusables are present. Added regressions in focus.traps.test.ts for both metadata-level and integration cases.

@RtlZeroMemory
RtlZeroMemory merged commit 5b9aae5 into main Feb 18, 2026
18 checks passed
@RtlZeroMemory
RtlZeroMemory deleted the focus-system-hardening branch February 19, 2026 17:45
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.

1 participant