Props are read-only inputs passed from parent to child components — they enable one-way data flow, with callback props providing the mechanism for children to communicate back to parents.
Props are passed from parent to child and are immutable — the receiving component must never modify its own props.
Content between component tags is passed as props.children — enables flexible composition where components don't need to know their content ahead of time.
Parents pass functions as props that children call to communicate upward — React's mechanism for inverse data flow.
PropTypes provide runtime validation (legacy); TypeScript interfaces provide compile-time safety (modern standard).
Props are external and read-only; state is internal and mutable. Both trigger re-renders when they change.
Props (short for "properties") are the primary mechanism for passing data between React components. They flow in one direction — from parent to child — and are read-only, meaning the receiving component cannot modify them.
A parent component passes data to a child by adding attributes to the JSX tag: <UserCard name="Alice" age={30} />. The child receives all props as a single object. The standard pattern is to destructure props in the function parameters: function UserCard({ name, age }) { ... }. Props can be any JavaScript value: strings, numbers, objects, arrays, functions, and even other React elements.
A component must never modify its own props. This is a core React rule — props are a snapshot of the data at render time. If a component needs to change data, it should use state internally or call a callback prop to request the parent to update.
Content placed between a component's opening and closing tags is passed as the special children prop: <Card><p>Hello</p></Card> — Card receives the paragraph as props.children. This enables flexible composition where a component doesn't need to know its content ahead of time. children can be any renderable content: JSX elements, strings, numbers, arrays, or even functions (the render props pattern).
Provide fallback values using JavaScript default parameters: function Button({ variant = 'primary', size = 'md' }) { ... }. This replaces the older Component.defaultProps API, which is being deprecated.
Children communicate back to parents through callback functions passed as props. The parent defines a handler function, passes it down, and the child calls it when an event occurs: <SearchInput onSearch={handleSearch} />. Inside SearchInput, calling onSearch(query) triggers the parent's handler. This is React's mechanism for "inverse data flow."
Two approaches exist:
prop-types package. Validates prop types during development and logs warnings in the console. UserCard.propTypes = { name: PropTypes.string.isRequired }. Useful but only catches errors at runtime.interface UserCardProps { name: string; age: number; } then function UserCard({ name, age }: UserCardProps). Catches errors before the code runs. The modern standard for React projects.The spread operator passes all properties of an object as individual props: <Button {...buttonProps} />. Useful for forwarding props to underlying components, but use sparingly — it makes it harder to see which props a component receives.
Props are external, passed from parent, read-only. State is internal, owned by the component, mutable via setter functions. A component re-renders when its props or state change. Data that comes from outside is a prop; data the component manages itself is state.
Props enable one-way data flow (parent → child) and are immutable. Callback props provide inverse data flow (child → parent). The children prop enables flexible composition. TypeScript interfaces are the modern way to type-check props, replacing PropTypes.
Fun Fact
The children prop is so flexible that it can be a function — this is the 'render props' pattern where a parent provides a function as children that the component calls with data: <DataProvider>{data => <Display data={data} />}</DataProvider>. This was the dominant code reuse pattern before hooks.