Skip to content

Props

Say you're building a Greeting component for a welcome banner, and every visitor who logs in needs to see their own name in it rather than one name hardcoded for everyone. A component that can only render a single fixed value cannot do that on its own. Props (short for properties) are how you pass data into a component from the outside, the same way an argument passes a value into a function. You write props on a component the same way you write attributes on an HTML tag, and the component reads them back through a single parameter.

jsx
function Greeting({ name }) {
  return <h1>Hello, {name}</h1>
}
// usage: <Greeting name="Ada" />

Greeting takes one prop, name. React collects every attribute you write on <Greeting> into a single object and passes that object as the component's first argument, so { name } here is destructuring that object to pull the name value straight out. Call <Greeting name="Ada" /> and name is "Ada" inside the function. Call it again with a different name and you get a different heading, from the same component.

Props flow in one direction: from where a component is used, down into the component itself. Inside Greeting, name behaves like a regular variable, but the component cannot change it: props are read-only. If a component needs data that changes over time, that's a job for state, covered a few chapters along.

Default values

If a prop might be missing, give it a default the same way you'd give any function parameter a default: an = in the destructuring pattern.

jsx
function Greeting({ name = 'friend' }) {
  return <h1>Hello, {name}</h1>
}

Call <Greeting /> with no name prop at all, and name falls back to 'friend'. Pass a name, and it overrides the default. This is ordinary JavaScript default parameter syntax, applied to the object React hands the component.

The children prop

Some components need to wrap other content instead of receiving it through an attribute. Write content between a component's opening and closing tags, and React passes it in automatically as a special prop called children.

jsx
function Card({ children }) {
  return <div className="card">{children}</div>
}

// usage:
// <Card>
//   <p>Whatever goes here becomes Card's children prop.</p>
// </Card>

children works exactly like any other prop: you read it through the same destructured parameter, and the component decides where to render it. The only difference is how it arrives, through the tags' contents rather than a named attribute.

Passing any JavaScript value

A prop can hold any JavaScript value: numbers, booleans, objects, arrays, even functions. Wrap the value in curly braces instead of quotes.

jsx
function UserCard({ user, onSelect }) {
  return <button onClick={() => onSelect(user.id)}>{user.name}</button>
}

// usage: <UserCard user={{ id: 1, name: 'Ada' }} onSelect={handleSelect} />

user here is an object, and onSelect is a function passed down so the component can call it. The button's onClick runs onSelect when someone clicks it, an event handler that the Events chapter covers in full next; take it on trust for now. This is how components communicate: data travels down through props, and behavior travels the same way, as a function the child can call.

One-way data flow

Props flow down the component tree on purpose. A parent passes data to a child, that child can pass it further down, and nothing flows back up through props. A component must never write to its own props object or mutate an object or array it received through a prop; treat everything you're handed as fixed.

That constraint is what keeps rendering predictable. When state changes somewhere and React re-renders the components affected by it, each render recomputes its JSX from that component's current props and state. If a component could reach up and mutate the props a parent gave it, the parent would lose any reliable picture of its own data, and tracing a bug would mean checking every child a value passed through instead of the one place it actually changed. Keeping props read-only keeps that traceable: any value in your UI has exactly one place where it's set.

Props get data into a component from the outside. A few chapters along, state covers how a component holds and updates its own data over time.

JunoProps are read-only Props are how a component receives information from whoever uses it, the same way an argument feeds a function. You read them off the destructured parameter, like { name }, and a component never changes the props it's handed. Give one a default value with = when it might be missing, and remember that anything you put between a component's tags arrives as its children prop.
JunoProps are read-only Props are the inputs to a component: destructure them off the parameter, default the ones that might be missing, and treat children as another prop that happens to arrive through the tags' contents instead of an attribute. They can hold anything, strings, objects, functions, so use them to pass data and behavior down together. Don't mutate what you're given; props stay read-only.
JunoProps are read-only Props carry data one way, down the tree, and that direction is load-bearing: a component that mutates its own props breaks the guarantee that a render reflects a known input. Default parameters and children are ordinary JavaScript and JSX syntax layered on top of a plain object. Keep props immutable on the component's side and rendering stays predictable, the property you're relying on everywhere else in React.

Next up: Lists and keys, where one component renders a whole array of data.