React 19: ref is a prop

Drop forwardRef, and read context with use(), even conditionally.

React docsreact.dev
Unlike React Hooks, use can be called within loops and conditional statements like if.
Reference: useRead docs ↗

From vercel-composition-patterns, rule react19-no-forwardref.

Fewer wrappers, real names

Wrap it in memo, then focus each input through its ref.

forwardRefBad
1 tree nodesname: ForwardRef
forwardRef<TextInput, Props>((props, ref) => …)
ref as a propGood
1 tree nodesname: ComposerInput
function ComposerInput({ ref, ...props })
function ComposerInput({ ref, ...props }: Props & { ref?: React.Ref<TextInput> }) {
  return <TextInput ref={ref} {...props} />
}

use() after an early return

Collapse both, then change the theme a few times.

useContext at the topBad
Details1 renders
0 renders while collapsed
hooks can't follow an early return
use() after the returnGood
Details1 renders
0 renders while collapsed
no read, no subscription
function Details({ open }: { open: boolean }) {
  if (!open) return null
  const theme = use(ThemeContext) // fine after an early return
  return <section className={theme}>…</section>
}

Why it matters, pros and cons

Why it matters

React 19 passes ref like any prop, so the wrapper only costs a name and a layer. use() can sit behind a condition.

Pros

  • No wrapper, no displayName, plain props type.
  • Components keep their own name in DevTools.
  • Context read only on the paths that need it.

Cons

  • React 19+ only; libraries on 18 still need forwardRef.
  • Class components still can't take ref as a prop.
  • Mixed codebases carry both styles for a while.