React.ComponentProps extracts the props type of an element or component. Pass the string "button" as its type argument and you get every valid button prop, ready to reuse and extend instead of re-typing by hand. It removes the busywork of copying a long attribute list.
What ComponentProps does
ComponentProps takes a JSX element or component type and returns its props type:
type ButtonProps = React.ComponentProps<"button">;ButtonProps now includes onClick, disabled, type, and the rest, without listing them. If the button element gains new attributes in a future React update, your type stays in sync automatically. The type argument can be any JSX tag string or a component type, and the props typing guide covers the interfaces and unions this utility builds on.
Reuse it in a wrapper
The common use is a custom component that forwards button props:
function Button(props: React.ComponentProps<"button">) {
return <button {...props} />;
}Button accepts every button attribute and passes them through. Callers use it like a native button, with any styling or logic you add on top. This is why most button and input wrappers accept the same attributes as the element they render.
Extract from your own component
ComponentProps also works with component types, not only tag strings. Pass a component type to extract its props:
function Button(props: React.ComponentProps<"button">) {
return <button {...props} />;
}
type ButtonProps = React.ComponentProps<typeof Button>;ButtonProps is now the exact type of Button's props. This is how a wrapper accepts whatever another component exposes, keeping the two APIs in sync automatically.
Tag strings give you native element props, while a component type gives you that component's own props. Both are valid arguments.
Extend with your own props
Combine the extracted type with your own fields using an intersection:
type ButtonProps = React.ComponentProps<"button"> & {
variant?: "primary" | "ghost";
};
function Button({ variant, ...rest }: ButtonProps) {
return <button className={variant} {...rest} />;
}The component now takes all button props plus a variant of its own. The rest parameter gathers the native button props for the spread. This is how a design system button keeps native behavior while adding its own API.
ComponentPropsWithoutRef for forwarding
ComponentProps includes the ref prop, which you rarely want in a props type. ComponentPropsWithoutRef omits it:
type ButtonProps = React.ComponentPropsWithoutRef<"button">;Use WithoutRef when you define props for a component that manages refs separately, so the ref type stays out of the way. ComponentPropsWithRef exists too and includes the ref, though forwardRef components handle refs more explicitly. When in doubt, use WithoutRef for props and pass the ref through forwardRef.
What to learn next
These utilities are the foundation for generic components. See how to type a generic component that adapts its props to a type parameter. ComponentProps keeps a library's API consistent as it grows.
Rune AI
Key Insights
- ComponentProps extracts an element's props type.
- Pass the tag name as a string type argument.
- Extend it with an intersection for your own props.
- ComponentPropsWithoutRef omits the ref prop.
- Extracted types stay in sync with React updates.
Frequently Asked Questions
What does React.ComponentProps do?
What is the difference between ComponentProps and ComponentPropsWithoutRef?
Can I add my own props to an extracted type?
Conclusion
React.ComponentProps extracts an existing element or component's props type so you can reuse it. Extend it with intersections for your own fields, and use ComponentPropsWithoutRef when refs are handled separately.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.