How to Pass Props to a Component in React

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>
  );
}
React page in Microsoft Edge rendering two Greeting components that received different name and city props
One component, two sets of props.

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
Two React ProductCard components in Edge rendered from string, number, boolean, array, object and function props, with the Webcam button disabled
The same card with different props; 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"}
Three React badges in Edge: one with default props, one from spread object props, and one with an extra id forwarded through rest props
Default, spread and forwarded props.

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>&#9733;</span>; }
function BellIcon() { return <span>&#128276;</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>
  );
}
React page in Edge with a button that received an icon element prop, an alert rendered from a component type prop and a list from a renderItem function prop
Element prop, component-type prop and render-function prop.

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
React TypeScript components in Edge: two Alert components with typed props and a primary and disabled secondary Button built from ComponentProps
The typed components in the browser.

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'.
Command Prompt showing TypeScript errors for React props: number expected, kind error not assignable, and missing property title
Wrong type, a value outside the union, and a missing required prop.
TaskCode
Pass a string / number<Card title="Lamp" price={45} />
Receive propsfunction Card({ title, price }) { ... }
Default valuefunction 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 propicon={<Star />} or Icon={Star}
TypeScriptfunction Card({ title }: { title: string })

Continue with these React component tutorials:

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).

Leave a Comment