Skip to content
patterns questions

Patterns · 2 of 10middle~1 min

What is the Render Props pattern?

#react#composition

Render Props

The render props pattern shares logic between components by passing a function as a prop. The function receives data and returns JSX.

Basic example

tsx
interface MousePosition { x: number; y: number; } function MouseTracker({ render }: { render: (pos: MousePosition) => React.ReactNode }) { const [pos, setPos] = useState({ x: 0, y: 0 }); return ( <div onMouseMove={(e) => setPos({ x: e.clientX, y: e.clientY })}> {render(pos)} </div> ); } // usage - full control over what gets rendered <MouseTracker render={({ x, y }) => ( <p>Mouse is at {x}, {y}</p> )} />

children as a function (most common variant)

tsx
function Toggle({ children }: { children: (on: boolean, toggle: () => void) => React.ReactNode }) { const [on, setOn] = useState(false); return <>{children(on, () => setOn(v => !v))}</>; } // usage <Toggle> {(on, toggle) => ( <div> <button onClick={toggle}>{on ? 'Hide' : 'Show'}</button> {on && <Modal />} </div> )} </Toggle>

Replaced by custom hooks

tsx
// the same MouseTracker logic as a hook - much cleaner function useMousePosition() { const [pos, setPos] = useState({ x: 0, y: 0 }); useEffect(() => { const handler = (e: MouseEvent) => setPos({ x: e.clientX, y: e.clientY }); window.addEventListener('mousemove', handler); return () => window.removeEventListener('mousemove', handler); }, []); return pos; } function Component() { const { x, y } = useMousePosition(); return <p>Mouse at {x}, {y}</p>; }

Render props solved logic sharing before hooks, but introduced deeply nested JSX. Custom hooks replaced most render prop patterns. You'll still encounter them as "children as a function" in libraries like Formik, Downshift and Headless UI ({({ open }) => ...}).

updated

did you know it?

related questions