type ButtonProps = React.ComponentPropsWithoutRef<"button"> & {
variant?: "primary" | "ghost";
};
function Button({ variant = "primary", className, ...rest }: ButtonProps) {
return <button className={`btn btn-${variant} ${className ?? ""}`} {...rest} />;
}
<Button type="submit" disabled onClick={save}>Save</Button>
Use React.ComponentProps<"button"> to get every native button prop, and intersect it with your own props using &. Then spread the remaining props onto the <button>.
React.ComponentProps<"button"> gives every prop the native element accepts:
onClickdisabledtypearia-*attributes, and so on
The explicit variants ComponentPropsWithoutRef and ComponentPropsWithRef also work.
Destructure the props you handle yourself, and spread the rest onto the element. Callers can then pass any native attribute without you listing it. Merge className instead of overwriting it.
Sometimes one of your props has the same name as a native prop but a different type. Remove the native one first with Omit<React.ComponentProps<"button">, "type">. Otherwise the intersection creates a conflicting type.
The same pattern works for any element, such as "input" or "a".
- Use
React.ComponentProps<"button">orComponentPropsWithoutRefto get all native props. - Intersect the native props with your custom props using
&. - Spread
...restonto the native element. - Use
Omitto remove native props that you redefine with a different type.