Back to all notes
Function Children Pattern: Pass a Function via Children
Share data from a parent and let consumers decide how to render it.
Introduction
The function children pattern passes a function as children so a parent can provide data and the consumer decides how to render it. It’s a powerful way to keep data and layout concerns separate.
Why this matters
Sometimes a parent owns data but doesn’t want to dictate the markup. By passing a function as children, the parent can provide values and the consumer decides how to render them.
The problem
We want to expose a user object while keeping the rendering flexible and colocated with the consumer.
Inefficient approach
Hard‑coding layout around data couples presentation to the provider:
function App() {
const user = { name: "John Doe", email: "john@example.com", role: "Developer" };
return (
<div>
<h1>Function Children Pattern</h1>
<h2>{user.name}</h2>
<p>{user.email}</p>
<p>{user.role}</p>
</div>
);
}
export default App;
The solution
Create a DataProvider that calls its children as a function.
function DataProvider({ children }) {
const user = { name: "John Doe", email: "john@example.com", role: "Developer" };
return children(user);
}
function App() {
return (
<div>
<h1>Function Children Pattern</h1>
<DataProvider>
{(user) => (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
<p>{user.role}</p>
</div>
)}
</DataProvider>
</div>
);
}
export default App;
Step-by-step
- Create
DataProviderthat owns theuserdata. - Accept
childrenas a function and call it withuser. - In the consumer, render UI inside the function with the provided
user. - Keep layout decisions in the consumer; keep data in the provider.
- Prefer this when the data shape is fixed but UI needs flexibility.
Tips
- Document the function signature (which values the parent passes).
- Prefer function children when a component controls data and the consumer controls layout.
- If the function grows complex, consider moving it to a named prop (render props).
Knowledge base
Problem snippet:
<h2>{user.name}</h2>
Solution snippet:
<DataProvider>
{(user) => <h2>{user.name}</h2>}
</DataProvider>