React Patterns & Best PracticesEntry 5 of 10
Forwarding Props
Passing any extra props a wrapper component receives on to the element it renders, using rest/spread syntax.
Notes
- Wrapper components (
Accordion,Button,Input) shouldn't need a prop declared for every possible attribute (className,id,aria-*, event handlers). - Collect the rest with
...propsand spread them onto the underlying element. - Type them with
ComponentPropsWithoutRef<'element'>so TypeScript knows every valid attribute. - Destructure the props the component handles itself first, so they aren't forwarded by accident.
What / Why / When
- What
Transparent attribute pass-through.
- Why
Reusable components stay flexible without a growing prop list.
- When
Components that wrap a single native element.
Code compare
// components/Accordion/AccordionTitle.tsx (with forwarding)import type { ComponentPropsWithoutRef } from "react";type AccordionTitleProps = ComponentPropsWithoutRef<"h3">;export default function AccordionTitle({ children, ...props }: AccordionTitleProps) { const { toggleItem } = useAccordionContext(); const id = useAccordionItemContext(); return ( <h3 {...props} onClick={() => toggleItem(id)}> {children} </h3> );}Attributes such as class, id, title, and aria-* written on a component's tag land on its host element automatically. For attributes the host can't use (form controls), make the component an attribute selector on the native element instead.
// Attribute selector: the native button IS the component's host@Component({ selector: "button[appButton]", template: `<ng-content />`, host: { class: "app-button" },})export class ButtonComponent {}<!-- type, disabled, aria-label, (click) all work natively --><button appButton type="submit" [disabled]="isPending()" aria-label="Save">Save</button>Differences and gotchas
- In React, place
{...props}before props you want to enforce (likeonClickabove), or after props the consumer should be able to override. - Angular has no rest props. Host attributes and attribute selectors cover the same need.
Quick reference
| React | Angular |
|---|---|
{ children, ...props } + {...props} | Attributes land on the host element |
ComponentPropsWithoutRef<'button'> | selector: 'button[appButton]' |