Skip to content

Export useFocusTrap hook - #1420

Merged
danielguillan merged 6 commits into
mainfrom
danielguillan/expose-focus-trap-hook
Jul 27, 2026
Merged

Export useFocusTrap hook#1420
danielguillan merged 6 commits into
mainfrom
danielguillan/expose-focus-trap-hook

Conversation

@danielguillan

@danielguillan danielguillan commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Resolves #1399

Exports useFocusTrap from the @primer/react-brand package.

The hook now creates missing refs automatically and captures previous focus when the trap activates.

List of notable changes:

  • exported useFocusTrap and FocusTrapHookSettings from the package root
  • updated useFocusTrap to create missing refs while preserving supplied object refs
  • added typed refs that work directly with specific HTML elements
  • moved previous-focus capture into useEffect so rendering remains SSR-safe
  • reset stored previous focus after cleanup so later activations capture the current element
  • added direct hook, lifecycle, and SSR regression coverage

Supporting resources (related issues, external links, etc):

Contributor checklist:

  • All new and existing CI checks pass
  • Tests prove that the feature works and covers both happy and unhappy paths
  • Any drop in coverage, breaking changes or regressions have been documented above
  • UI Changes contain new visual snapshots (generated by adding update snapshots label to the PR)
  • All developer debugging and non-functional logging has been removed
  • Related issues have been referenced in the PR description

Reviewer checklist:

  • Check that pull request and proposed changes adhere to our contribution guidelines and code of conduct
  • Check that tests prove the feature works and covers both happy and unhappy paths
  • Check that there are not other open Pull Requests for the same update/change

Screenshots:

N/A

Copilot-Session: b43bee82-7a2d-40d0-95c2-9b053bdc6075
@danielguillan
danielguillan requested a review from a team as a code owner July 22, 2026 14:29
Copilot AI review requested due to automatic review settings July 22, 2026 14:29
@changeset-bot

changeset-bot Bot commented Jul 22, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: bbb6f4b

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

This PR includes changesets to release 9 packages
Name Type
@primer/react-brand Minor
@primer/brand-docs Minor
@primer/brand-css Minor
@primer/brand-primitives Minor
@primer/brand-e2e Minor
@primer/brand-fonts Minor
@primer/brand-mcp Minor
@primer/brand-config Minor
@primer/brand-storybook Minor

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

@github-actions

Copy link
Copy Markdown
Contributor

🟢 No design token changes found

Copilot AI 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.

Pull request overview

This PR makes the useFocusTrap hook part of the public @primer/react-brand API by exporting it from the package root, and updates the hook to always provide stable containerRef/initialFocusRef values via useProvidedRefOrCreate when refs are not supplied.

Changes:

  • Exported useFocusTrap from packages/react/src/index.ts.
  • Updated useFocusTrap to accept optional refs and to create stable fallback refs when not provided.
  • Added a changeset documenting the new export + behavior.
Show a summary per file
File Description
packages/react/src/index.ts Exports useFocusTrap from the package root.
packages/react/src/hooks/useFocusTrap.ts Uses useProvidedRefOrCreate to ensure stable refs and updates types accordingly.
.changeset/tidy-traps-focus.md Declares a minor release and documents the new export + ref behavior.

Review details

  • Files reviewed: 3/3 changed files
  • Comments generated: 2
  • Review effort level: Low

Comment thread packages/react/src/hooks/useFocusTrap.ts Outdated
Comment thread packages/react/src/index.ts
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

🟢 Unit test coverage changes found

Unit test coverage has been updated through this PR.

Changes: 1 new tests, 0 removed tests, 0 improved, 0 decreased

Component/Hook Statements Functions Branches Change
useFocusTrap 100.0% 100.0% 86.7% NEW

@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

🟢 Bundle size report

CheckMainBranchChange
UMD — full bundle (JS)101.39 kB101.65 kB⬆️ +266 B (+0.3%)
UMD — full bundle (CSS)66.97 kB66.98 kB⬆️ +8 B (+0.0%)
ESM — full bundle (JS + CSS)1.51 MB1.52 MB⬆️ +4.66 kB (+0.3%)
ESM — tree-shaken simple (Button)69.94 kB70.29 kB⬆️ +360 B (+0.5%)
ESM — tree-shaken complex (ActionMenu)78.83 kB79.14 kB⬆️ +318 B (+0.4%)

@github-actions

Copy link
Copy Markdown
Contributor

🟢 No visual differences found

Our visual comparison tests did not find any differences in the UI.

Copilot-Session: b43bee82-7a2d-40d0-95c2-9b053bdc6075
Copilot-Session: b43bee82-7a2d-40d0-95c2-9b053bdc6075

Copilot AI 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.

Review details

  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Low

Comment thread packages/react/src/hooks/useFocusTrap.ts
Comment thread packages/react/src/hooks/useFocusTrap.ts Outdated
Copilot-Session: b43bee82-7a2d-40d0-95c2-9b053bdc6075

Copilot AI 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.

Review details

Comments suppressed due to low confidence (1)

packages/react/src/hooks/useFocusTrap.ts:60

  • restoreFocusOnCleanUp currently only restores focus when the previously focused element is an HTMLElement. document.activeElement can be a non-HTMLElement (e.g. a focusable SVG element with tabindex), so focus restoration will silently no-op even though the setting says it restores focus to the element that was focused before activation. Consider restoring focus for any element that exposes a focus() method instead of restricting to HTMLElement only.
    if (settings?.restoreFocusOnCleanUp && previousFocusedElement.current instanceof HTMLElement) {
      previousFocusedElement.current.focus()
    }
    previousFocusedElement.current = null
  • Files reviewed: 5/5 changed files
  • Comments generated: 0 new
  • Review effort level: Low

@danielguillan
danielguillan requested a review from rezrah July 22, 2026 16:48

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.

Does this need to be a separate file @danielguillan? Can we add the test case to the useFocusTrap.test.tsx file?

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.

I believe so. My understanding is that Jest’s  node  environment is file-scoped.

Comment thread packages/react/src/hooks/useFocusTrap.test.tsx Outdated

@rezrah rezrah left a comment

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.

LGTM. Thanks for fixing this Dani.

Copilot-Session: 28a6bc72-61a7-4142-933a-df469ee7461e
Copilot-Session: 28a6bc72-61a7-4142-933a-df469ee7461e
@danielguillan
danielguillan merged commit 654b881 into main Jul 27, 2026
17 checks passed
@danielguillan
danielguillan deleted the danielguillan/expose-focus-trap-hook branch July 27, 2026 07:52
@primer primer Bot mentioned this pull request Jul 23, 2026
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.

Export useFocusTrap as part of the public API

3 participants