React Essentials — Components, JSX, Props, State & MoreEntry 5 of 11
Props Are Not Forwarded Automatically
A wrapper component only passes on the props it explicitly uses; everything else is ignored.
Notes
If Examples renders <Section id="examples" /> but Section never reads id, the id is ignored. It does not reach the inner <section> element. Props must be used and set explicitly.
There are two fixes:
- Explicit: destructure the prop and set it:
<section id={id}>. Fine for one or two props. - Rest and spread (scalable): collect every prop you didn't destructure with
...restand spread it onto the inner element. Callers can then addid,className,style,aria-*, event handlers, orrefwithout the wrapper declaring each one.
In React 19, ref is a regular prop, so forwardRef is no longer needed for function components.
What / Why / When
- What
Rest and spread props.
- Why
Prevents wrappers from swallowing attributes; makes design-system components behave like native elements.
- When
Building wrappers around native elements (buttons, inputs, sections).
- Use case
A
Buttoncomponent that still acceptstype,disabled, andaria-label.
Code compare
import type { ComponentProps, ReactNode } from "react";// ❌ id is ignoredfunction SectionIgnored({ title, children }: { title: string; children: ReactNode }) { return ( <section> <h2>{title}</h2> {children} </section> );}// ✅ Explicit: works, but every prop must be listedfunction SectionExplicit({ title, id, children,}: { title: string; id?: string; children: ReactNode;}) { return ( <section id={id}> <h2>{title}</h2> {children} </section> );}// ✅ Rest and spread: forwards everything elsetype SectionProps = ComponentProps<"section"> & { title: string };export function Section({ title, children, ...rest }: SectionProps) { return ( <section {...rest}> <h2>{title}</h2> {children} </section> );}Attributes placed on a component tag land on the host element (<app-section>) automatically, so nothing is ignored. To make them land on a native element, use an attribute selector so the host is the native element:
import { Component } from "@angular/core";@Component({ selector: "button[appButton]", template: `<ng-content />`, host: { class: "btn" },})export class ButtonComponent {}Differences and gotchas
- React needs explicit props or
{...rest}. Angular gets attribute fall-through on the host element for free. - An Angular component with an element selector (
app-button) wraps an inner<button>, and attributes on<app-button>won't reach that inner button. The attribute selector pattern is the idiomatic fix.
Quick reference
| React | Angular |
|---|---|
id={id} or ...rest + {...rest} | Attributes fall through to the host element |
| Wrap a native element | selector: 'button[appButton]' |