To pass props to a component in React, write them like HTML attributes where you use the component: <Greeting name="Olivia" city="Austin" />. The component receives them as one object, usually destructured in the function parameters: function Greeting({ name, city }). This guide covers React props in functional components step by step: every value type (including functions for child-to-parent communication), default values, spreading and rest props, how to pass a component as a prop, reading all props, and typing props with TypeScript.
Every example was built with React 19.3.0, Vite 8.3.0 and TypeScript 7.0.2 (npx vite build) and opened in Microsoft Edge; clicks were real mouse events, and the outputs are the browser console messages or tsc output. Reference: Passing Props to a Component on react.dev.
Pass props to a functional component
function Greeting({ name, city }) { // props arrive as one object
return <p>Hello {name} from {city}!</p>;
}
export default function App() {
return (
<div>
<Greeting name="Olivia" city="Austin" /> {/* pass props like HTML attributes */}
<Greeting name="Mateo" city="Chicago" />
</div>
);
}
Props flow one way: from the parent to the child. The child should treat them as read-only; if a value must change, the parent keeps it in state and passes the new value down.
Passing different kinds of props
Strings can be quoted; every other JavaScript value goes in curly braces. A prop with no value is true. Passing a function is how a child talks back to its parent:
function ProductCard({ title, price, inStock, tags, seller, onAdd }) {
return (
<div style={{ border: "1px solid #ccc", padding: 12, marginBottom: 8, width: 360 }}>
<strong>{title}</strong> ${price.toFixed(2)} {inStock ? "In stock" : "Sold out"}
<div>Tags: {tags.join(", ")} | Seller: {seller.name} ({seller.rating}/5)</div>
<button className="add" disabled={!inStock} onClick={() => onAdd(title)}>Add to cart</button>
</div>
);
}
export default function App() {
const handleAdd = (title) => console.log("added to cart:", title); // child calls the parent's function
return (
<div>
<ProductCard
title="Desk Lamp" // string
price={45} // number: use braces
inStock // boolean true (shorthand)
tags={["office", "led"]} // array
seller={{ name: "BrightCo", rating: 4.6 }} // object
onAdd={handleAdd} // function
/>
<ProductCard title="Webcam" price={69.5} inStock={false} tags={["video"]}
seller={{ name: "CamWorks", rating: 4.1 }} onAdd={handleAdd} />
</div>
);
}
Console output after clicking “Add to cart” on the first card:
added to cart: Desk Lamp
inStock={false} disables the second button.Default values, spreading and rest props
Give a prop a default with a destructuring default (color = "steelblue"). Use {...obj} to pass all properties of an object as props, and ...rest to collect props you did not name and forward them to an element:
function Badge({ label, color = "steelblue", size = "small", ...rest }) {
console.log("Badge props:", JSON.stringify({ label, color, size, ...rest }));
return (
<span {...rest} style={{ background: color, color: "white", padding: size === "large" ? 10 : 4, marginRight: 8 }}>
{label}
</span>
);
}
export default function App() {
const vip = { label: "VIP", color: "darkorange", size: "large", title: "Premium member" };
return (
<p>
<Badge label="New" /> {/* default color and size */}
<Badge {...vip} /> {/* spread an object as props */}
<Badge label="Beta" id="beta-badge" /> {/* extra props go to ...rest */}
</p>
);
}
Console output:
Badge props: {"label":"New","color":"steelblue","size":"small"}
Badge props: {"label":"VIP","color":"darkorange","size":"large","title":"Premium member"}
Badge props: {"label":"Beta","color":"steelblue","size":"small","id":"beta-badge"}
Destructuring defaults are the modern replacement for Component.defaultProps, which React 19 no longer supports for function components.
Pass a component as a prop
There are three common patterns: pass a ready JSX element, pass the component itself (use a capitalized prop name so JSX treats it as a component), or pass a function that returns JSX. The children prop, the content between the tags, is a fourth, built-in variant:
function StarIcon() { return <span>★</span>; }
function BellIcon() { return <span>🔔</span>; }
// 1. pass an element: <Button icon={<StarIcon />} />
function Button({ icon, children }) {
return <button>{icon} {children}</button>;
}
// 2. pass a component type (capitalized prop name) and render it inside
function Alert({ Icon, message }) {
return <p><Icon /> {message}</p>;
}
// 3. pass a render function that receives data from the child
function List({ items, renderItem }) {
return <ul>{items.map((item) => <li key={item}>{renderItem(item)}</li>)}</ul>;
}
export default function App() {
return (
<div>
<Button icon={<StarIcon />}>Save to favorites</Button>
<Alert Icon={BellIcon} message="You have 3 new notifications" />
<List items={["react", "vite"]} renderItem={(item) => <code>{item.toUpperCase()}</code>} />
</div>
);
}
Get all props of a component
Without destructuring, the parameter is the whole props object. key is used by React itself and is not passed to the component:
function UserRow(props) {
console.log("UserRow props:", Object.keys(props).join(", "));
const { user, highlight } = props; // destructure what you need
return <li style={{ fontWeight: highlight ? "bold" : "normal" }}>{user.name}, {user.role}</li>;
}
export default function App() {
const users = [{ id: 1, name: "Ava", role: "admin" }, { id: 2, name: "Ben", role: "editor" }];
return (
<ul>
{users.map((u) => <UserRow key={u.id} user={u} highlight={u.role === "admin"} />)}
</ul>
);
}
Console output:
UserRow props: user, highlight
UserRow props: user, highlight
React component props with TypeScript
Describe the props with a type (or interface) and annotate the parameter. Use ReactNode for children, ? for optional props, and ComponentProps<"button"> to accept every attribute of a native element:
import type { ComponentProps, ReactNode } from "react";
type AlertProps = {
title: string;
kind?: "info" | "warning"; // optional, only two allowed values
count: number;
children: ReactNode; // anything React can render
};
function Alert({ title, kind = "info", count, children }: AlertProps) {
return (
<div style={{ borderLeft: `6px solid ${kind === "info" ? "steelblue" : "orange"}`, padding: 8, marginBottom: 8 }}>
<strong>{title}</strong> ({count}) {children}
</div>
);
}
// all props of a normal <button>, plus our own "variant"
type ButtonProps = ComponentProps<"button"> & { variant?: "primary" | "secondary" };
function Button({ variant = "primary", ...rest }: ButtonProps) {
return <button {...rest} style={{ background: variant === "primary" ? "#1d4ed8" : "#e5e7eb", color: variant === "primary" ? "white" : "black" }} />;
}
export default function App() {
return (
<div>
<Alert title="Build finished" count={3}>All checks passed.</Alert>
<Alert title="Disk space" kind="warning" count={1}>Less than 10% free.</Alert>
<Button type="button" onClick={() => console.log("primary clicked")}>Deploy</Button>
<Button variant="secondary" disabled>Cancel</Button>
</div>
);
}
Console output after clicking Deploy:
primary clicked
npx tsc --noEmit reports no errors for this file. The value of typed props shows when something is wrong; the compiler finds each mistake before the app runs:
type AlertProps = { title: string; kind?: "info" | "warning"; count: number };
function Alert({ title, kind = "info", count }: AlertProps) {
return <p>{kind}: {title} ({count})</p>;
}
export const good = <Alert title="Saved" count={1} />;
export const bad1 = <Alert title="Saved" count="1" />; // wrong type
export const bad2 = <Alert title="Saved" kind="error" count={1} />; // not an allowed value
export const bad3 = <Alert count={2} />; // missing required prop
tsc output:
src/AlertErrors.tsx(8,42): error TS2322: Type 'string' is not assignable to type 'number'.
src/AlertErrors.tsx(9,42): error TS2322: Type '"error"' is not assignable to type '"info" | "warning" | undefined'.
src/AlertErrors.tsx(10,22): error TS2741: Property 'title' is missing in type '{ count: number; }' but required in type 'AlertProps'.
| Task | Code |
|---|---|
| Pass a string / number | <Card title="Lamp" price={45} /> |
| Receive props | function Card({ title, price }) { ... } |
| Default value | function Card({ price = 0 }) |
| Pass all fields of an object | <Card {...product} /> |
| Child to parent | <Card onAdd={handleAdd} />, then onAdd(title) in the child |
| Component as prop | icon={<Star />} or Icon={Star} |
| TypeScript | function Card({ title }: { title: string }) |
Continue with these React component tutorials:
- Use React components with children
- Pass a component as a prop in React
- Call a function in a child component
- Convert a React component to TypeScript
Frequently asked questions
How do I pass props to a component in React?
Add them as attributes where you render the component, <Profile name="Ava" age={31} />, and read them from the first parameter: function Profile({ name, age }).
How do I pass a component as a prop?
Pass an element (icon={<Star />}) and render {icon}, or pass the component (Icon={Star}) and render <Icon />.
How do I pass data from a child to a parent?
Pass a function as a prop and call it from the child with the data: onSelect(item).
How do I set default props in a functional component?
Use destructuring defaults: function Button({ size = "medium" }).
Can a component change its own props?
No. Props are read-only. Keep changing values in the parent’s state and pass them down.
How do I type props in TypeScript?
Define a type, type Props = { title: string; count?: number }, and write function Card({ title, count }: Props).
Bijay Kumar is a 13-time Microsoft MVP with more than 18 years in software development, and the founder of Python Guides and TSinfo Technologies. He started out building .NET and SharePoint solutions at HP, TCS and KPIT before moving into Python, machine learning and AI, and he also builds web apps with TypeScript and React. He writes the tutorials here himself, and every example is run before publishing so you see the real output. More about Bijay · Microsoft MVP profile · LinkedIn