Render Props
A render prop is when you pass a function as a prop to a component, and that function returns what should be rendered.
Instead of a component showing you a fixed piece of content, it calls a function you provide and says "here's some data I have. You decide what to show."
This documentation covers two render prop patterns:
- RenderProp for simple content rendering without prop manipulation.
- BindingRenderProp for intelligent prop merging with the element that you provide.
RenderProp
type RenderProp<Props = HTMLAttributes<HTMLElement>, ElementType = ReactNode> =
| ElementType
| ((props: Props) => ElementType)The RenderProp type accepts either:
ReactNode: Regular JSX elements, strings, numbers, etc.Function: A render function that receives typed props and returnsReactNode
Usage
Render Prop Function
Pass a function to access the computed props directly in JSX:
<SomeContext>
{(contextValue) => (
<div>Dynamic content based on: {contextValue.someProperty}</div>
)}
</SomeContext>Standard Children (ReactNode)
Pass regular JSX as children and they render as normal:
<SomeContext>
<div>Static content</div>
</SomeContext>Implementation Example
import {RenderProp} from "@qualcomm-ui/react-core/system"
interface User {
name: string
}
interface UserContextProps {
children: RenderProp<User>
}
function UserContext({children}: UserContextProps): ReactNode {
const user: User = {name: "John"}
return renderProp(children, user)
}
function UserPanel() {
return (
<UserContext>
{(user: User) => <div>Welcome, {user.name}!</div>}
</UserContext>
)
}BindingRenderProp
type BindingRenderProp<
Props = HTMLAttributes<HTMLElement>,
Element = ReactElement,
> = Element | ((props: Props) => Element)The BindingRenderProp type accepts either:
ReactElement: An existing JSX element whose props are intelligently merged with computed propsFunction: A render function that receives typed props and returnsReactElement
Usage
Existing Elements (ReactElement)
When you pass a JSX element, its props are intelligently merged with the computed props from the render function:
<PopoverTrigger>
<button onClick={userHandler}>Click me</button>
</PopoverTrigger>Render Prop Function
Pass a function to build elements with the computed props:
<PopoverTrigger>
{(bindings) => <button {...bindings}>Custom button</button>}
</PopoverTrigger>Implementation Example
Use bindingRenderProp to handle both patterns in your components:
import {BindingRenderProp} from "@qualcomm-ui/react-core/system"
interface PopoverBindings {
onClick: () => void
"aria-expanded": boolean
}
interface PopoverTriggerProps {
children: BindingRenderProp<PopoverBindings>
}
function PopoverTrigger({children}: PopoverTriggerProps): ReactElement {
const bindings: PopoverBindings = {
onClick: () => console.log("toggle"),
"aria-expanded": false,
}
return bindingRenderProp(children, bindings)
}
function PopoverButton() {
return (
<PopoverTrigger>
<button onClick={() => console.log("user click")}>Toggle Popover</button>
</PopoverTrigger>
)
}Prop Merging Behavior
When passing existing elements, props are intelligently merged:
- Event handlers: Both user and computed handlers execute
- CSS classes: Merged using
clsx - Styles: Combined
- Other props: User props override computed props