What is Composition?
Radix UI Primitives are built with a composable API design. This means components are designed to be combined and nested to create complex UI patterns while maintaining full control over the rendered markup. The key principle: one component renders one DOM element (or no DOM element at all).The Composable API
Instead of a single component with many props, Radix provides multiple sub-components that work together:Benefits of Composition
Flexibility
Insert your own elements anywhere in the component tree. Add wrappers, change order, or customize markup.
Control
Direct access to each DOM element means full control over styling, event handlers, and attributes.
Predictability
Easy to understand what HTML will be rendered. One component = one DOM element.
Simplicity
No complex prop configurations. Compose the pieces you need like building blocks.
1-to-1 Mapping
Each Radix component maps directly to a single DOM element:- Refs work as expected - Forward a ref to a Radix component, and it points to the actual DOM node
- Event handlers work naturally - Add
onClick,onMouseEnter, etc., directly to components - Styling is straightforward - Apply classes or styles exactly where you need them
- Inspection is easy - The React component tree matches the DOM tree
Some components like
Dialog.Root and Accordion.Root don’t render any DOM element - they only manage state and context.Composition Patterns
Basic Composition
Nest components to build the structure you need:Adding Custom Elements
You can add your own elements anywhere:Conditional Rendering
Components work naturally with conditional rendering:Mapping Over Data
Easily create dynamic lists:The asChild Prop
One of the most powerful composition features is the asChild prop. It allows you to merge Radix’s functionality with your own elements.
Without asChild
By default, Radix components render their own element:
With asChild
Use asChild to merge functionality into your own element:
Using with Custom Components
You can useasChild with your own components:
Using with Icons and Wrappers
Accessing DOM Refs
Since components map 1-to-1 with DOM elements, refs work naturally:Event Handler Composition
You can add your own event handlers, and they’ll be composed with Radix’s internal handlers:Event handlers are composed, not replaced. Both your handler and Radix’s internal handler will run.
Controlled vs Uncontrolled
Composition works with both controlled and uncontrolled patterns:Uncontrolled (Internal State)
Controlled (External State)
Building Wrapper Components
You can create your own wrapper components while maintaining composability:Composition Anti-Patterns
Avoid these common mistakes:Don’t Skip Required Parts
Don’t Break Component Hierarchy
Composition vs Configuration
Radix favors composition over configuration:
Composition wins because:
- More flexible - you control the markup
- More predictable - you see exactly what renders
- Better TypeScript support - each component has specific types
- Easier to customize - no need to learn complex prop APIs
Next Steps
Accessibility
Learn about accessibility features
Slot Component
Deep dive into the Slot utility
Components
Browse all available components
Styling
Learn about styling approaches