Ref
A direct handle on a real DOM element, or on a value that survives re-renders, so you can focus it, measure it, or scroll it.
See it
What it is
A ref does two jobs. First, it hands you the real DOM node so you can do the imperative things a framework does not model: .focus(), .scrollIntoView(), .getBoundingClientRect() for measuring, .play() on a video, getContext('2d') on a canvas, or handing the element to a non-React library like GSAP or a map SDK. Second, it is a mutable box that survives re-renders without causing one, which is where timer ids and previous values live.
Every framework has the idea: useRef in React (and ref as a plain prop since React 19, so no more forwardRef), template refs in Vue, bind:this in Svelte. The rule of thumb: if the screen should change when the value changes, it is state, not a ref.
Gotcha: ref.current is null on the first render and during server-side rendering, and it only fills in after mount, so guard every access. Mutating a ref never triggers a re-render, so reading one during render gives you stale or empty output. If you need to run code the instant a node appears, use a callback ref (which can return a cleanup function in React 19) instead of an effect that pokes at .current.
Ask AI for it
Identify the single imperative DOM operation this component actually needs (focusing a field, scrolling an element into view, measuring a box, calling .play(), handing a node to a non-React library) and name which element it targets. Add one ref to that element, typed for that element (useRef<HTMLInputElement | null>(null), not a loose HTMLElement), and pass it to the element's ref prop. Perform the operation from the handler or effect that should trigger it, or from a callback ref if it has to happen the moment the node mounts, and never touch .current during render. Null-check every access, since .current is null before mount and during server rendering. Anything the UI renders belongs in state, not in the ref. If you find you want a second unrelated imperative behavior, say so instead of stacking it onto the same ref.