Skip to content

Update useMergedRefs to be React 19 compatible and public + deprecate useRefObjectAsForwardedRef and useProvidedRefOrCreate - #7672

Merged
iansan5653 merged 6 commits into
mainfrom
update-use-merged-refs
Mar 18, 2026
Merged

Update useMergedRefs to be React 19 compatible and public + deprecate useRefObjectAsForwardedRef and useProvidedRefOrCreate#7672
iansan5653 merged 6 commits into
mainfrom
update-use-merged-refs

Conversation

@iansan5653

@iansan5653iansan5653 commented Mar 17, 2026

Copy link
Copy Markdown
Contributor

Currently there are three solutions for unifying an external (forwarded) ref with an internal ref object or callback ref: useMergedRefs, useRefObjectAsForwardedRef, and useProvidedRefOrCreate. All of these essentially completely overlap in applicability but have different signatures. Also, none of them are compatible with React 19 callback ref cleanup functions. And useRefObjectAsForwardedRef has performance issues because it updates refs too often, while useProvidedRefOrCreate has significant type safety issues requiring casts and typechecker disables.

This PR is the first in a stack of PRs that will attempt to modernize and unify this solution. This first step is to update useMergedRefs to be React 19 compatible by supporting callback ref cleanup functions. This is done by returning a cleanup function that React 19 will call while providing React 18-compatible null handling behavior.

This PR also exposes useMergedRefs publicly and deprecates the other solutions. In followup PRs I will migrate the existing uses to this hook.

This update also improves type safety and ergonomics, particularly in React 19, by accepting undefined, null, and non-mutable ref object values. This allows for optional ref props, which will be more common as React 19 deprecates the forwardRef HOC.

Finally, added some tests.

Note: This change does change the hook from accepting any number of arguments to only accepting two. This is all that's necessary 99% of the time, and so I don't think it's worth the increase in complexity and performance cost to support any number of input refs. If a consumer really needs to combine more refs, they can just call the hook again.

Changelog

New

  • Exposes new useMergedRefs hook that can merge two refs into a single combined ref

Changed

  • Deprecates useRefObjectAsForwardedRef; see doc comment for migration instructions
  • Deprecates useProvidedRefOrCreate; see doc comment for migration instructions

Removed

Rollout strategy

  • Patch release
  • Minor release
  • Major release; if selected, include a written rollout or migration plan
  • None; if selected, include a brief description as to why

Testing & Reviewing

Merge checklist

@iansan5653
iansan5653 requested a review from a team as a code ownerMarch 17, 2026 16:37
@changeset-bot

changeset-botBot commented Mar 17, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: bbfc0cb

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

This PR includes changesets to release 1 package
NameType
@primer/reactMinor

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-actionsgithub-actionsBot added the integration-tests: recommended This change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm label Mar 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Action required

👋 Hi, this pull request contains changes to the source code that github/github-ui depends on. If you are GitHub staff, test these changes with github/github-ui using the integration workflow. Check the integration testing docs for step-by-step instructions. Or, apply the integration-tests: skipped manually label to skip these checks.

CopilotAI left a comment

Copy link
Copy Markdown
Contributor

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 modernizes ref-merging in @primer/react by making useMergedRefs React 19–compatible (supporting callback ref cleanup functions), exporting it as a public hook, and deprecating overlapping/less-safe ref utilities.

Changes:

  • Introduces a new public useMergedRefs hook that returns a combined ref callback with React 19 cleanup support (and React 18-compatible null behavior).
  • Deprecates useRefObjectAsForwardedRef and useProvidedRefOrCreate with migration guidance.
  • Adds unit tests and updates exports to include the new hook.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
FileDescription
packages/react/src/internal/hooks/useMergedRefs.tsRemoves the previous internal-only merged refs implementation.
packages/react/src/hooks/useMergedRefs.tsAdds the new public, React 19-compatible merged refs hook (with cleanup support).
packages/react/src/hooks/useMergedRefs.hookDocs.jsonAdds hookDocs metadata for documentation generation.
packages/react/src/hooks/tests/useMergedRefs.test.tsxAdds tests for object refs, callback refs, and React 19 cleanup behavior.
packages/react/src/index.tsExposes useMergedRefs in the public package entrypoint.
packages/react/src/hooks/index.tsExposes useMergedRefs via the hooks barrel export.
packages/react/src/tests/snapshots/exports.test.ts.snapUpdates the exports snapshot to include useMergedRefs.
packages/react/src/hooks/useRefObjectAsForwardedRef.tsMarks the hook as deprecated and provides a migration example.
packages/react/src/hooks/useProvidedRefOrCreate.tsMarks the hook as deprecated and provides a migration example.
packages/react/src/Banner/Banner.tsxSwitches import to the public useMergedRefs hook.
packages/react/src/Details/Details.tsxSwitches import to the public useMergedRefs hook.

Comment threadpackages/react/src/index.ts
Comment threadpackages/react/src/hooks/useMergedRefs.ts
Comment threadpackages/react/src/hooks/useMergedRefs.hookDocs.json Outdated
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

@TylerJDevTylerJDev left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice, thanks for this contribution! This looks good to me ✨ I think the plan to deprecate and migrate current usage is solid too!

@primer-integration

Copy link
Copy Markdown

👋 Hi from github/github-ui! Your integration PR is ready: https://github.com/github/github-ui/pull/16346

@primer-integration

Copy link
Copy Markdown

Integration test results from github/github-ui:

Passed CI  Passed
Passed VRT  Passed
Passed Projects  Passed

All checks passed!

@iansan5653
iansan5653 added this pull request to the merge queueMar 18, 2026
Merged via the queue into main with commit 77735f9Mar 18, 2026
53 checks passed
@iansan5653
iansan5653 deleted the update-use-merged-refs branch March 18, 2026 19:40
@primerprimerBot mentioned this pull request Mar 18, 2026
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

integration-tests: recommendedThis change needs to be tested for breaking changes. See https://arc.net/l/quote/tdmpakpm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

@iansan5653@TylerJDev