EmpireUI
Get Pro
← Blog8 min read#render props#react#patterns

Render Props in React 2026: Dead Pattern or Still Useful?

Render props aren't dead — but they're not your first choice anymore either. Here's when the pattern still earns its keep in 2026 React codebases.

Developer writing React component code on a laptop screen

What Render Props Actually Are (Quick Recap)

A render prop is a function prop — you pass a function to a component, and that component calls it to decide what to render. That's the whole idea. The component handles state and behavior, you handle the output. It's a clean inversion of control that was genuinely brilliant when React didn't have hooks.

The canonical example you've probably seen a hundred times looks like this: ``jsx <Mouse render={({ x, y }) => ( <h1>Mouse is at {x}, {y}</h1> )} /> ` The Mouse` component tracks coordinates internally. It doesn't care what you do with them — you get the data and render whatever you want. Separation of concerns without a higher-order component wrapper cluttering your component tree.

Worth noting: the children prop itself can be a function, which is arguably more elegant than a prop named render. Libraries like React Router, Formik (pre-v2), and Downshift leaned hard on this style. If you've used any of those, you've already written render props without maybe calling them that.

The pattern got popular around 2017-2018, React 16.3 era, right before hooks landed. It solved a real problem. Then hooks landed in React 16.8 (February 2019) and suddenly everyone declared render props dead. That declaration was... premature.

Why Hooks Didn't Kill Render Props Completely

Hooks replaced the *stateful logic sharing* use case almost entirely. Need mouse position across components? Write a useMousePosition hook. Done. No wrapper, no nesting, no extra component in your DevTools tree. For that job, hooks are strictly better.

But render props solve a *different* problem that hooks don't touch: controlled rendering delegation. When a parent component genuinely needs to hand off rendering decisions to the consumer — and the consumer needs to inject custom JSX into a specific slot inside a complex component — render props are still the right tool. It's not about sharing state. It's about flexible composition.

Consider a virtualized list that manages its own scroll, overflow, and row positioning, but needs the caller to provide the row template. A hook can't do that. The list component has to call something at render time to produce the row JSX. That something is a render prop (or children as a function). ``jsx <VirtualList data={items} rowHeight={48} renderRow={({ item, index, style }) => ( <div style={style} className="flex items-center gap-3"> <Avatar src={item.avatar} /> <span>{item.name}</span> </div> )} /> ``

Honestly, most developers abandoned render props too enthusiastically. They reached for hooks even in cases where a render prop would've been 10 lines instead of 40. The right question isn't 'hooks or render props' — it's 'am I sharing stateful logic, or delegating rendering?' Those are different jobs.

That said, I'd still default to hooks 90% of the time. But that 10% exists and it matters.

Where Render Props Still Win in 2026

Animation libraries are the clearest survivor. When you need a library component to hand you animation state so you can apply it to *your* arbitrary JSX, render props are the natural shape. Framer Motion's AnimatePresence pattern and various transition components use this exact approach — the library owns the lifecycle, you own the markup.

Headless UI components are another obvious home. Libraries like Radix UI and Headless UI expose components that manage accessibility logic (keyboard navigation, ARIA attributes, focus management) but render nothing opinionated. You provide the visuals. A render prop or asChild pattern lets the library inject props onto whatever element you choose. If you're building custom glassmorphism components or a heavily styled design system, headless components with render props are how you get accessible behavior without fighting default styles.

Form field adapters are a third strong case. Imagine a Field component that wraps validation state, error messaging, and label association. It doesn't know whether the input is a text box, a date picker, or a custom component you built. Passing render or using children as a function lets you slot in anything: ``jsx <Field name="email" validate={validateEmail}> {({ value, onChange, error, touched }) => ( <div className="flex flex-col gap-1"> <input value={value} onChange={onChange} className={touched && error ? 'border-red-500' : 'border-gray-300'} /> {touched && error && <span className="text-sm text-red-500">{error}</span>} </div> )} </Field> ``

Quick aside: compound components (the <Select> + <Select.Option> pattern) sometimes get lumped in with render props discussions but they're architecturally different. Compound components use React context internally. Render props explicitly pass function props. Don't conflate them.

If you're wiring up a complex interactive UI — say a component from the Empire UI library that has its own internal state but needs to accept custom content in multiple slots — render props give you a clean API surface that consumers understand immediately, without needing to read internal hook implementations.

The Performance Concerns (and Whether They Matter)

The classic knock against render props is that inline function props trigger unnecessary re-renders. Every time the parent renders, a new function reference is created, the child sees a prop change, and it re-renders even if the actual behavior hasn't changed. In React 18+, this is real but less catastrophic than it sounds.

You can sidestep the problem with useCallback: ``jsx const renderRow = useCallback( ({ item, style }) => ( <div style={style}>{item.name}</div> ), [] // stable if item references don't change ); <VirtualList data={items} renderRow={renderRow} /> `` In practice, the performance hit only bites when the child component is expensive *and* you're not memoizing. For most UI components rendering at 60fps, it's not the bottleneck you're worried about.

Look, if you're building a list with 5,000 rows that each do heavy computation, yes — profile it and wrap things in React.memo plus useCallback. If you're building a modal with a render prop to inject the header content, you'll never notice the re-render cost. Don't optimize what you haven't measured.

One more thing — React's compiler (shipping more broadly in late 2025 and into 2026) automatically memoizes function references in many cases. This weakens the performance argument against render props considerably. The gap between 'plain render prop' and 'memoized render prop' is shrinking at the framework level.

Render Props vs Hooks: Choosing Between Them

Here's the decision tree I actually use. Is the consumer just getting data or event handlers back? Hook. Does the component need to call into consumer code *during its own render* to produce output? Render prop. That one question resolves 95% of cases.

A side-by-side is worth seeing: ``jsx // Hook: sharing stateful logic function MouseTracker() { const { x, y } = useMousePosition(); // consumer owns rendering return <div>Mouse: {x}, {y}</div>; } // Render prop: delegated rendering function Tooltip({ renderContent, children }) { const [visible, setVisible] = useState(false); return ( <div onMouseEnter={() => setVisible(true)} onMouseLeave={() => setVisible(false)} className="relative" > {children} {visible && ( <div className="absolute top-full left-0 z-10"> {renderContent()} {/* tooltip decides nothing about this JSX */} </div> )} </div> ); } ` The Tooltip` can't be a hook. It needs to mount and unmount JSX based on hover state, inside its own render tree. A hook can't do that.

Worth noting: you can — and often should — combine both. The Tooltip above might internally use a useTooltipPosition hook to calculate 8px offsets and flip direction when near viewport edges, while still exposing a render prop for the content. They're not rivals.

When you're building UI components that other developers will consume — like anything in a design system or a component library — render props are often the better public API. They're visible in JSX, easy to see in DevTools, and the data flow is explicit. Hooks are great internally but can feel like magic from the outside.

Common Mistakes to Avoid

The biggest mistake: overusing render props where a simple slot pattern with children would do. If you find yourself writing <Card render={() => <p>Hello</p>} />, just use <Card><p>Hello</p></Card>. Render props earn their weight when you're passing data back up *with* the rendering delegation. If there's no data flowing back, it's overkill.

Second mistake: deeply nested render props. This was the 'callback hell' version of React circa 2018. Three render-prop components nested inside each other became completely unreadable. Hooks fixed this for stateful logic. If you find yourself nesting render props, stop and ask whether the outer component could just expose a hook instead — or whether the whole thing should be a compound component. ``jsx // Don't do this <Auth render={({ user }) => ( <Theme render={({ colors }) => ( <Router render={({ location }) => ( <App user={user} colors={colors} location={location} /> )} /> )} /> )} /> // Do this function App() { const user = useAuth(); const colors = useTheme(); const location = useLocation(); return <AppContent user={user} colors={colors} location={location} />; } ``

Third mistake: forgetting to type the render prop properly in TypeScript. A render prop that takes unknown and returns ReactNode is almost as bad as any. Be specific: ``ts type VirtualListProps<T> = { data: T[]; rowHeight: number; renderRow: (props: { item: T; index: number; style: React.CSSProperties }) => React.ReactNode; }; ` Generic render props in TypeScript are honestly elegant when you get them right. That type parameter T flows through cleanly and consumers get full autocomplete on the item` shape.

In practice, the teams I've seen struggle most with render props are teams that adopted hooks in 2019, never looked back, and forgot the underlying problem render props were solving. They end up building hooks that return JSX (which is weird) or component factories (which is worse) instead of just... using a render prop.

The Verdict: Still Alive, Just Narrower

Render props in 2026 aren't a pattern you'd architect a new app around — but they're not deprecated either. They're specialized. Hooks won the 'share stateful logic' war decisively. Render props held onto 'controlled rendering delegation' and they're not giving that up.

The real sign of a mature React developer isn't knowing hooks vs render props — it's knowing when each is the right fit. If you're building headless components, virtualized lists, animation wrappers, or flexible form fields, you'll reach for render props naturally. If you're extracting data-fetching logic or UI state shared across multiple components, you won't.

One more thing — if you're curious how this plays out in real component design, it's worth studying how headless UI libraries handle styling flexibility. When you're building something like a box shadow generator or complex interactive widgets, the same delegation problem comes up: the tool owns the logic, but the output needs to match the consumer's design system. That's render props territory.

So is the pattern dead? No. Is it your default? Also no. It's a sharp tool in a specific situation — and now you know what that situation looks like.

FAQ

Are render props still relevant with React hooks in 2026?

Yes, for a specific use case: rendering delegation, where a component needs to call consumer-provided JSX during its own render. Hooks cover stateful logic sharing, but they can't replace render props in headless components or virtualized lists.

Do render props cause performance problems?

Inline function props create new references on each render, which can trigger unnecessary child re-renders. Wrap them in useCallback if the child is expensive, but don't optimize prematurely — React's compiler handles many cases automatically now.

When should I use a render prop instead of a hook?

When the component needs to invoke your code *during its own render* to produce output — like a tooltip rendering custom content, or a list rendering custom rows. If you're just getting data back, use a hook.

Can I combine hooks and render props in the same component?

Absolutely. A component can use hooks internally for its own state and logic, while exposing a render prop as its public API. This is common in headless UI libraries and animation wrappers.

Free components in 40 styles
React & Tailwind, copy-paste ready.
Browse →

Read next

React Compound Components Pattern: Flexible APIs Without Prop Hell15 Custom React Hooks That Will Save You Hundreds of LinesTailwind vs CSS Modules in 2026: Which One Should You Actually Use?shadcn/ui Alternatives: What to Use When shadcn Isn't Enough