composeRefs
Compose multiple React refs into a single ref callback. Essential when a component needs an internal ref and must also forward an external ref prop.
composeRefs merges any number of React refs into one callback. It is the low-level utility used to construct a composed ref. In component render call sites, use useComposedRefs so the callback identity stays stable across renders.
It is used internally by select, menu, tabs, radio, checkbox, navigation-list, and command-palette and is installed automatically when you add any of those components.
Installation
npm packages: @diffgazer/add is on npm. pnpm add -D @diffgazer/add puts dgadd on pnpm exec, and npx @diffgazer/add <command> runs it without the install. Components also install without dgadd from the hosted registry: npx shadcn add https://r.b4r7.dev/r/ui/<item>.json.
dgadd ships in @diffgazer/add on npm: pnpm add -D @diffgazer/add puts it on pnpm exec, and npx @diffgazer/add runs it without the install.
UI components require Tailwind CSS v4. Local copy mode imports src/styles/styles.css; package mode uses @diffgazer/ui CSS from the installed package.
The file is placed at lib/compose-refs.ts in your project.
The render-time recipes below use the companion hook. Install it with pnpm exec dgadd add ui/composed-refs; its registry item includes compose-refs.
API
Parameters
Returns
A single RefCallback<T> that, when called with a DOM element (or null on unmount), forwards the value to every ref in the list.
Usage
Forward an external ref while keeping an internal one
Merge a context ref with an external ref
Three refs at once
Notes
- Stable render-time refs — use
useComposedRefswhen the composed callback is passed from a component render. CallingcomposeRefsinline creates a new callback, so React detaches and reattaches it on every render. - Low-level construction — use
composeRefswhen callback identity is already stable, including inside theuseComposedRefsimplementation. - No
forwardRefneeded — both utilities support the React 19ref-as-prop pattern. - Null-safe —
nullandundefinedrefs are silently skipped. You can pass an optional consumer ref without guarding. - Order-independent — refs are called left-to-right, but all receive the same element value, so order only matters if you have side effects in a callback ref.
- No runtime dependencies — pure TypeScript, no React peer API beyond the
Reftypes.