# useComposedRef

> Keeps a ref to your own element while still forwarding it to whatever ref the parent passed in.

Docs: https://hextaui.com/docs/use-composed-ref
Markdown: https://hextaui.com/docs/use-composed-ref.md

```tsx title="components/examples/use-composed-ref/demo.tsx"
"use client"

import * as React from "react"

import { Button } from "@/components/ui/button"
import { useComposedRef } from "@/hooks/use-composed-ref"

function CharacterInput({ ref, ...props }: React.ComponentProps<"input">) {
  const [inputRef, setRef] = useComposedRef<HTMLInputElement>(ref)
  const [length, setLength] = React.useState(0)

  return (
    <div className="flex h-9 w-full items-center gap-2 rounded-md bg-muted pe-3 focus-within:ring-3 focus-within:ring-focus-ring">
      <input
        ref={setRef}
        {...props}
        onChange={(event) => {
          props.onChange?.(event)
          setLength(event.target.value.length)
        }}
        className="h-full min-w-0 flex-1 bg-transparent ps-3 text-sm outline-none focus-visible:outline-hidden pointer-coarse:text-touch"
      />
      <button
        type="button"
        hidden={length === 0}
        onClick={() => {
          const input = inputRef.current
          if (input) {
            input.value = ""
            setLength(0)
            input.focus()
          }
        }}
        className="text-xs text-muted-foreground hover:text-foreground"
      >
        Clear
      </button>
    </div>
  )
}

export function UseComposedRefDemo() {
  const ref = React.useRef<HTMLInputElement>(null)

  return (
    <div className="flex w-full max-w-xs flex-col gap-3">
      <CharacterInput ref={ref} aria-label="Search" placeholder="Search" />
      <Button variant="outline" size="sm" onClick={() => ref.current?.focus()}>
        Focus from the parent
      </Button>
    </div>
  )
}
```

## Installation

### CLI

```bash
npx shadcn@latest add https://hextaui.com/r/use-composed-ref.json
```

This adds the hook and anything it depends on.

### Manual

Copy and paste the following code into your project.

```ts title="hooks/use-composed-ref.ts"
import * as React from "react"

function useComposedRef<T>(ref: React.Ref<T> | undefined) {
  const inner = React.useRef<T | null>(null)
  const setRef = React.useCallback(
    (node: T | null) => {
      inner.current = node
      if (typeof ref === "function") {
        ref(node)
      } else if (ref) {
        ref.current = node
      }
    },
    [ref]
  )
  return [inner, setRef] as const
}

export { useComposedRef }
```

Update the import paths to match your project setup.

## Usage

```tsx
import { useComposedRef } from "@/hooks/use-composed-ref"
```

```tsx
function SearchInput({ ref, ...props }: React.ComponentProps<"input">) {
  const [inputRef, setRef] = useComposedRef<HTMLInputElement>(ref)

  React.useEffect(() => {
    inputRef.current?.select()
  }, [inputRef])

  return <input ref={setRef} {...props} />
}
```

In React 19, `ref` is a regular prop. When your component also needs the element for itself, you have two refs and only one `ref` attribute. This hook gives you an object ref to read, plus a callback that fills both refs.

## The problem it solves

```tsx
function SearchInput({ ref, ...props }: React.ComponentProps<"input">) {
  const inputRef = React.useRef<HTMLInputElement>(null)
  return <input ref={inputRef} {...props} />
}
```

This compiles, but the parent's `ref` is dropped, so `ref.current` stays `null` in the parent. With `useComposedRef`, both the parent and the component get the element.

- The returned `inputRef` is a normal `RefObject`, so you can pass it to hooks that expect one, like `useAutosize` or `useInvalidShake`.
- `setRef` keeps the same identity while the parent's ref does, so React doesn't detach and reattach it on every render.
- Works with object refs, callback refs and no ref at all.

## Composed or merged

Use `useComposedRef` when you combine exactly one forwarded ref with your own object ref, which is most components. Use [useMergedRef](https://hextaui.com/docs/use-merged-ref) when you combine more than two, when one of them is a callback ref from another hook, or when a forwarded callback ref returns a React 19 cleanup function. `useComposedRef` calls a callback ref with `null` on detach instead of running its cleanup.

## API reference

### useComposedRef(ref)

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `ref` | `Ref<T> \| undefined` | – | The ref your component received. |

| Returns | Description |
| --- | --- |
| `[0] RefObject<T \| null>` | Your own ref to the element. |
| `[1] (node: T \| null) => void` | Pass to the element's ref. Fills both refs. |

### Used by

`Input`, `Textarea`, `NativeSelect`, `Field` and `InputGroup`.

## Notes for AI assistants

- Install a component with the shadcn CLI: `npx shadcn@latest add https://hextaui.com/r/<name>.json`. It adds the source, the HextaUI theme tokens and any HextaUI components it depends on. `https://hextaui.com/r/all.json` installs every component.
- The code is then owned by the project, like shadcn/ui. There is no HextaUI npm package. HextaUI is MIT licensed and free for personal and commercial use.
- Behavior and accessibility come from Base UI (`@base-ui/react`). Compose with the `render` prop, not `asChild`.
- Styling uses Tailwind CSS v4 with theme tokens. Merge classes with `cn` from the `cn` package.
- Icons come from `@tabler/icons-react`.
- Import components from `@/components/ui/<name>`, hooks from `@/hooks/<name>` and utilities from `@/lib/<name>`.

Every HextaUI doc: https://hextaui.com/llms.txt
