Composition
A guide to composing Base UI components with your own React components.
Composing custom React components
Use the render
prop to compose a Base UI part with your own React components.
For example, most triggers render a <button>
by default.
The code snippet below shows how to use a custom button instead.
<Menu.Trigger render={<MyButton size="md" />}>
Open menu
</Menu.Trigger>
The custom component must forward the ref
, and spread all the received props on its underlying DOM node.
Composing multiple components
In situations where you need to compose multiple Base UI components with custom React components, render
props can be nested as deeply as necessary.
Working with Tooltip is a common example.
<Dialog.Root>
<Tooltip.Root>
<Tooltip.Trigger
render={
<Dialog.Trigger
render={
<Menu.Trigger render={<MyButton size="md" />}>
Open menu
</Menu.Trigger>
}
/>
}
/>
<Tooltip.Portal>...</Tooltip.Portal>
</Tooltip.Root>
<Dialog.Portal>...</Dialog.Portal>
</Dialog.Root>
Changing the default rendered element
You can also use the render
prop to override the rendered element of the component.
For example, Menu.Item
renders a <div>
by default.
The code snippet below shows how to render it as an <a>
element so that it works like a link.
import * as React from 'react';
import { Menu } from '@base-ui-components/react/menu';
export default () => (
<Menu.Root>
<Menu.Trigger>Song</Menu.Trigger>
<Menu.Portal>
<Menu.Positioner>
<Menu.Popup>
<Menu.Item render={<a href="base-ui.com" />}>
Add to Library
</Menu.Item>
</Menu.Popup>
</Menu.Positioner>
</Menu.Portal>
</Menu.Root>
);
Each Base UI component renders the most appropriate element by default, and in most cases, rendering a different element is recommended only on a case-by-case basis.
Render function
If you are working in an extremely performance-sensitive application, you might want to pass a function to the render
prop instead of a React element.
<Switch.Thumb
render={(props, state) =>
<span {...props}>
{state.checked ? <CheckedIcon /> : <UncheckedIcon />}
</span>
}
/>
Using a function gives you complete control over spreading props and also allows you to render different content based on the component’s state.