Props
A component that always shows the same thing is not very useful. Props (short for properties) let a parent component pass data to a child, so one ProductCard can show a cricket bat, a football or a racket depending on what you give it.
In this lesson you will pass and read props, set default values, use the special children prop to wrap content, and learn why a component must never change its own props.
Passing and reading props
You pass props the same way you write HTML attributes. Fixed text goes in quotes; every other value goes in curly braces. React collects all of them into one object and passes it as the first argument of your component function.
import { createRoot } from "react-dom/client";
function ProductCard({ name, price, inStock, rating }) {
return (
<article style={{ border: "1px solid #ddd", padding: 10, marginBottom: 8 }}>
<h3>{name}</h3>
<p>₹{price.toLocaleString("en-IN")}</p>
<p>Rating: {rating} / 5</p>
<p>{inStock ? "In stock" : "Out of stock"}</p>
</article>
);
}
function Shop() {
return (
<>
<ProductCard name="English willow bat" price={4999} inStock={true} rating={4.6} />
<ProductCard name="Leather ball" price={650} inStock={false} rating={4.1} />
<ProductCard name="Batting gloves" price={1299} inStock rating={4.4} />
</>
);
}
createRoot(document.getElementById("root")).render(<Shop />);function ProductCard({ name, price, inStock, rating }) uses destructuring to pull the four values out of the props object. Without destructuring you would write function ProductCard(props) and then props.name, props.price and so on. Both are correct; destructuring is shorter and shows at a glance which props the component expects.
Two details are worth noticing. price={4999} passes a number; price="4999" would pass a string. And inStock on its own, with no value, is shorthand for inStock={true}.
Props can be any value
Props are not limited to strings and numbers. You can pass arrays, objects, functions and even JSX:
<OrderSummary
items={["Idli", "Vada", "Filter coffee"]}
customer={{ name: "Ananya", city: "Kochi" }}
onCancel={() => console.log("cancelled")}
icon={<span>☕</span>}
/>Passing a function as a prop is how a child tells its parent that something happened, such as a click. You will use that pattern a lot from Handling Events onwards.
Default values
If a parent does not pass a prop, its value is undefined. Give a prop a default value with the normal JavaScript default syntax inside the destructuring:
import { createRoot } from "react-dom/client";
function Avatar({ name, size = 48, photo = "https://course.ethicscomputer.in/assets/samples/avatar.svg" }) {
return (
<figure style={{ display: "inline-block", margin: 8, textAlign: "center" }}>
<img src={photo} alt={name} width={size} height={size} style={{ borderRadius: "50%" }} />
<figcaption>{name}</figcaption>
</figure>
);
}
function Team() {
return (
<>
<Avatar name="Rohan" />
<Avatar name="Meera" size={80} />
<Avatar name="Farhan" size={32} />
</>
);
}
createRoot(document.getElementById("root")).render(<Team />);The default is used only when the prop is missing or undefined. If a parent passes size={null} or size={0}, the default is not used.
The children prop
Whatever you put between a component's opening and closing tags arrives as a special prop called children. This lets you build wrapper components such as cards, panels and page layouts that do not need to know what is inside them.
import { createRoot } from "react-dom/client";
function Card({ title, children, tone = "info" }) {
const colours = { info: "#087ea4", warning: "#b45309" };
return (
<section style={{ border: `2px solid ${colours[tone]}`, borderRadius: 8, padding: 12, marginBottom: 10 }}>
<h3 style={{ marginTop: 0, color: colours[tone] }}>{title}</h3>
{children}
</section>
);
}
function App() {
return (
<>
<Card title="Exam timetable">
<p>Maths on Monday, Physics on Wednesday.</p>
</Card>
<Card title="Fee reminder" tone="warning">
<p>Last date for the hostel fee is 10 November.</p>
<button>Pay ₹18,500</button>
</Card>
</>
);
}
createRoot(document.getElementById("root")).render(<App />);The Card component draws the border and title; the parent decides the contents. This idea is called composition, and it is the main way to reuse layout in React.
Props are read-only
Props flow one way: from parent to child. A component must treat its props as read-only and never change them.
function Price({ amount }) {
amount = amount * 1.18; // avoid: reassigning a prop is confusing
return <p>₹{amount}</p>;
}
function PriceWithGst({ amount }) {
const withGst = amount * 1.18; // good: compute a new local value
return <p>₹{withGst.toFixed(2)}</p>;
}Changing a prop object, such as props.customer.city = "Pune", is worse: it changes the parent's data behind its back, breaking the purity rule from the previous lesson. When a value needs to change over time (because of a click or typing), it belongs in state, which you will learn in State with useState. The parent can then pass the new value down as a prop.
Spreading props
Sometimes a component forwards all of its props to a child. The spread syntax {...props} passes every property at once:
function PrimaryButton(props) {
return <button className="btn-primary" {...props} />;
}
// <PrimaryButton type="submit" disabled>Save</PrimaryButton>This is handy for small wrapper components around HTML elements. Do not overuse it: spreading hides which props a component really uses.
Common mistakes
- Passing numbers as strings.
price="499"is the text"499", soprice + 1gives"4991". Useprice={499}. - Forgetting the braces when destructuring.
function Card(title)receives the whole props object intitle. Writefunction Card({ title }). - Modifying props. Never assign to a prop or change a prop object. Compute new local values or use state.
- Expecting
childrento be an array. It can be a single element, a string, an array or nothing. Render it with{children}and let React handle it.
Key points
- Props pass data from a parent to a child, written like HTML attributes.
- A component receives one props object; destructure it in the parameter list.
- Props can be any JavaScript value: strings, numbers, arrays, objects, functions and JSX.
- Set defaults with
{ size = 48 }; they apply only when a prop isundefined. - Content between a component's tags arrives as the
childrenprop. - Props are read-only; values that change over time belong in state.
Exercise
Write a Student component with props name, course, year (default 1) and children. It should show the name in a heading, a line such as "BCA, year 2", and then the children. Render three students, one without a year prop, and give one of them a paragraph of children such as "Class representative".
Show solution
import { createRoot } from "react-dom/client";
function Student({ name, course, year = 1, children }) {
return (
<div style={{ borderBottom: "1px solid #ccc", padding: 8 }}>
<h3>{name}</h3>
<p>{course}, year {year}</p>
{children}
</div>
);
}
function ClassList() {
return (
<>
<Student name="Priya Sharma" course="BCA" year={2}>
<p>Class representative</p>
</Student>
<Student name="Aarav Gupta" course="BCA" />
<Student name="Isha Khan" course="B.Com" year={3} />
</>
);
}
createRoot(document.getElementById("root")).render(<ClassList />);Aarav has no year prop, so the default 1 is used. Priya's paragraph arrives as children and appears below her course line.
Quick Quiz
1. How does a component receive its props?
React collects all attributes into one props object; function components usually destructure it.
2. What is children in <Card><p>Hello</p></Card>?
Content between a component's tags arrives as the special children prop.
3. When is a destructuring default such as size = 48 used?
JavaScript defaults apply only to undefined; 0 and null are real values.
4. A value must change when the user clicks a button. Where should it live?
Props are read-only; values that change over time are stored in state.
Learn React with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
