Skip to contents

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.

index.tsx

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.

index.tsx

How props are merged

When the render prop receives an element, the part’s props and the element’s props are merged onto a single element. For example, this toolbar button renders a menu trigger:

index.tsx

The rendered <button> gets:

  • className="menu-trigger toolbar-button": class names are combined, starting with the render element’s.
  • style={{ color: 'blue', padding: 4 }}: style objects are merged, and the render element’s values win.
  • Both click handlers, starting with handleMenuClick. Calling event.preventBaseUIHandler() skips every handler that runs after it, so calling it in handleMenuClick also skips handleToolbarClick. Some parts call it internally.
  • Both refs: toolbarButtonRef and menuTriggerRef point to the same element.

For other attributes set on both, such as id or title, the render element’s value wins. Component props like disabled are read by each part separately, so a value on the render element doesn’t override the part’s own.

The render prop merges props with mergeProps, except for refs: mergeProps keeps only the rightmost ref, while the render prop keeps all of them.

Changing the default rendered element

You can also use the render prop to override the rendered element of the component.

For example, <Accordion.Header> renders an <h3> element by default. The code snippet below shows how to render it as an <h2> element so that it fits the heading hierarchy of the page.

index.tsx

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.tsx

Using a function gives you complete control over spreading props and also allows you to render different content based on the component’s state.