useRender

Hook for enabling a render prop in custom components.

The useRender hook lets you build custom components that provide a render prop to override the default rendered element.

Examples

A render prop for a custom Text component lets consumers use it to replace the default rendered p element with a different tag or component.

Base UI React 1.8.0

Text component rendered as a paragraph tag

Text component rendered as a strong tag
FineSoft Stencil

Text component rendered as a paragraph tag

Text component rendered as a strong tag

The callback version of the render prop enables more control of how props are spread, and also passes the internal state of a component.

Base UI React 1.8.0
FineSoft Stencil

Merging props

The mergeProps function merges two or more sets of React props together. It safely merges three types of props:

  1. Event handlers, so that all are invoked
  2. className strings
  3. style properties

mergeProps merges objects from left to right, so that subsequent objects’ properties in the arguments overwrite previous ones. Merging props is useful when creating custom components, as well as inside the callback version of the render prop for any Base UI component.

Using mergeProps in the render callback

Merging refs

When building custom components, you often need to control a ref internally while still letting external consumers pass their own—merging refs lets both parties have access to the underlying DOM element. The ref option in useRender enables this, which holds an array of refs to be merged together.

In React 19, React.forwardRef() is not needed when building primitive components, as the external ref prop is already contained inside props. Your internal ref can be passed to ref to be merged with props.ref:

React 19

In older versions of React, you need to use React.forwardRef() and add the forwarded ref to the ref array along with your own internal ref.

The examples above assume React 19, and should be modified to use React.forwardRef() to support React 18 and 17.

React 18 and 17

TypeScript

To type props, there are two interfaces:

  • useRender.ComponentProps for a component’s external (public) props. It types the render prop and HTML attributes.
  • useRender.ElementProps for the element’s internal (private) props. It types HTML attributes alone.
Typing props

Migrating from Radix UI

Radix UI uses an asChild prop, while Base UI uses a render prop. Learn more about how composition works in Base UI in the composition guide.

In Radix UI, the Slot component lets you implement an asChild prop.

Radix UI Slot component

In Base UI, useRender lets you implement a render prop. The example below is the equivalent implementation to the Radix example above.

Base UI render prop

Render prop and polymorphism

The render prop is primarily designed for composing event handlers and behavioral props. In most cases it should render the same tag as the default element.

Using render for polymorphism (rendering a different tag) requires more care, as some default props may not be valid on the new element. For example, type="button" is only valid on a <button>. Since the component can’t know what element render will produce at render time and before hydration, props like these need an explicit signal. This is why Base UI’s Button provides a nativeButton prop to control which defaults are applied.

Stencil API

useRender returns a Stencil VNode. Call it from a Stencil component’s render() method, or mount the result with the public render(vnode, container) function. It is not a React hook. For native VNode SSR, use renderVNodeToString(vnode) from the same entry; custom-element declarations can then pass through finesoft-components/hydrate. The examples use this serializer and the same consumer render function on the server and in the browser.

Parameter
Stencil contract
render
Stencil VNode, or (props, state) => VNode
defaultTagName
Native tag name; defaults to div
createElement
Optional local Stencil h factory for a separately built application
props
Native Stencil props; events use the mergeProps contract
state
Passed to the callback and converted to data-* attributes
stateAttributesMapping
Per-state mappings returning attributes or null
ref
Object ref, callback ref, or an array of refs
enabled
false returns null without calling the render callback

Boolean true state becomes an empty attribute; falsy values are omitted. Attribute names use the lowercased state key. Explicit props override generated attributes. Default buttons use type="button", and default images use alt=""; explicit props can override these defaults.

VNode overrides merge classes, styles and handlers and retain their own children. Callback overrides receive the resolved props and state directly. Object and callback refs from props, render and ref are combined. Callback cleanup functions run on replacement or unmount; legacy callbacks receive null. Stable refs stay attached across updates.

When building your own Stencil component in another project, use a local factory backed by that project’s h. Stencil detects render capabilities from local h() calls: the dynamic props argument retains event, ref, class and style support, and the explicit SVG branch retains SVG support. Passing only an imported h reference does not tell the consuming compiler which features this utility needs. Standalone consumers using the package’s h and render use the default factory.

The useRender.ComponentProps, ElementProps, Parameters, RenderProp, ReturnValue, and State types use Stencil VNodes and native events. React elements, React component functions and React hooks are not accepted as Stencil render overrides.

API reference

Usage

Parameters

useRender.Parameters

renderReactElement | function
Name
Description

The React element or a function that returns one to override the default element.

Type
refUnion
Name
Description

The ref to apply to the rendered element.

Type
stateTState
Name
Description

The state of the component, passed as the second argument to the render callback. State properties are automatically converted to data-* attributes.

Type
stateAttributesMappingStateAttributesMapping<TState>
Description

Custom mapping for converting state properties to data-* attributes.

Type
Example
propsRecord<string, unknown>
Name
Description

Props to be spread on the rendered element. They are merged with the internal props of the component, so that event handlers are merged, className strings and style properties are joined, while other external props overwrite the internal ones.

Type
enabledboolean
Description

If false, the hook will skip most of its internal logic and return null. This is useful for rendering a component conditionally.

Type
defaultTagNamekeyof React.JSX.IntrinsicElements
Description

The default tag name to use for the rendered element when render is not provided.

Type

Return value

useRender.StateHide

useRender.ComponentPropsHide

useRender.ElementPropsHide

useRender.ParametersHide

useRender.RenderPropHide

useRender.ReturnValueHide

HTMLPropsHide

UseRenderComponentPropsHide

UseRenderElementPropsHide

UseRenderParametersHide

UseRenderRenderPropHide

UseRenderReturnValueHide

UseRenderStateHide