React Default Props

In the last lesson you learned React Passing Data with Props, so now you know how to send data into a component. This lesson is about what happens when someone forgets to pass a prop, and how default props give it a safe fallback value.

🤔 Why do we need default props?

Imagine you build a Button component and share it across your app. Other people use it. Sometimes they pass every prop, and sometimes they forget one. You can’t control that, so your component has to be ready for the missing case.

Here’s why defaults matter:

  • Props are optional by nature - React does not force anyone to pass a prop. If they skip it, you just get undefined for that prop.
  • Missing props break the UI - An empty label, a missing color, a blank image. The component still renders, but it looks wrong.
  • Reusable components need safe fallbacks - A good shared component should never crash or look broken just because one prop was left out.
  • Defaults make the API friendly - People can pass only what they care about, and the rest fills in with sensible values.

What 'undefined' means here

When a prop is not passed, React does not throw an error. The prop is simply undefined. Default props are how you replace that undefined with a real value.

💥 The problem: no default

Let me show you the pain first. Here is a Button component that reads label and color straight from props, with no fallback.

function Button({ label, color }) {
return <button style={{ backgroundColor: color }}>{label}</button>;
}
function App() {
return (
<div>
<Button label="Save" color="green" />
<Button /> {/* ❌ nothing passed */}
</div>
);
}

Walk through what happens with each button:

  • The first <Button label="Save" color="green" /> works fine. It shows a green button that says “Save”.
  • The second <Button /> passes nothing, so label is undefined and color is undefined.
  • The button still renders, but it has no text inside it, and backgroundColor is undefined, so it falls back to the browser default look.

That second button is the broken case. An empty button with no text is useless, and the user has no idea what it does.

What renders

[ Save ] <- green button, has text
[ ] <- empty button, no text, no color

✅ The fix: default values in destructuring

Now the modern way to fix this. When you destructure props in the function arguments, you can give each one a default value right there with =, so if the prop comes in as undefined, the default takes over.

function Button({ label = "Click me", color = "blue" }) {
return <button style={{ backgroundColor: color }}>{label}</button>;
}
function App() {
return (
<div>
<Button label="Save" color="green" /> {/* uses passed values */}
<Button /> {/* ✅ uses defaults: "Click me", blue */}
</div>
);
}

Here is what changed and why it works:

  • { label = "Click me", color = "blue" } is plain JavaScript destructuring with defaults. The = says “if this is undefined, use this value instead”.
  • The first button still shows “Save” in green, because passed values always win over defaults.
  • The second <Button /> now shows a blue button that says “Click me”. No more empty, broken button.
  • You write the fallback in one place, so every use of the component is protected.

The key idea is that a default only kicks in when the prop is undefined. Pass a real value and your value is used. Pass nothing and the default is used.

Defaults only fill undefined

Remember, the default fires only when the prop is undefined. If you pass an empty string label="" on purpose, that is a real value, so the default will NOT replace it. Same for 0 and false — those are real values too.

🧱 The legacy way: Component.defaultProps

Before destructuring defaults became common, React had its own way to set defaults. You attached a defaultProps object to the component. You will still see this in older code, so it helps to recognize it.

function Button({ label, color }) {
return <button style={{ backgroundColor: color }}>{label}</button>;
}
// legacy approach — still works on function components but no longer preferred
Button.defaultProps = {
label: "Click me",
color: "blue",
};

A few things to know about this older style:

  • It does the same job. If label is not passed, React fills it in from defaultProps.
  • The values sit in a separate object below the component, away from where you actually use the props.
  • The React team has said defaultProps on function components is being phased out, and the destructuring default is the recommended way now.

Prefer the destructuring default

For modern function components, set defaults right in the destructuring: function Button({ label = "Click me" }). Keep defaultProps only for reading old code. The destructuring style keeps the fallback next to the prop, so it is easier to read and is the recommended approach today.

🌍 Where defaults really help

Defaults shine the moment a prop is optional or a component is meant to be reused. Some everyday cases:

  • Optional settings - A color, a size, a variant. Most of the time you want a normal default, and let people override it only when they need to.
  • Reusable UI components - Buttons, cards, badges, avatars. These get used in many places. A safe default means they never render broken.
  • Placeholder content - An avatar with no image can default to a generic picture. A user card with no name can default to “Guest”.
  • Counts and toggles - A count that defaults to 0, or an isOpen that defaults to false, so the component has a sane starting state.

Here is a small UserCard that stays friendly even when half the props are missing.

function UserCard({ name = "Guest", role = "Member" }) {
return (
<div className="user-card">
<h3>{name}</h3>
<p>{role}</p>
</div>
);
}
function App() {
return (
<div>
<UserCard name="Riya" role="Admin" /> {/* shows Riya / Admin */}
<UserCard name="Arjun" /> {/* shows Arjun / Member */}
<UserCard /> {/* shows Guest / Member */}
</div>
);
}

Notice how each card still renders something sensible. Even the empty <UserCard /> shows “Guest” and “Member” instead of two blank lines. That is the whole point of a fallback.

🧩 What You’ve Learned

  • ✅ When a prop is not passed, React gives you undefined, which can leave the UI empty or broken.
  • ✅ The modern way to set a default is right in the destructuring: function Button({ label = "Click me" }).
  • ✅ A default value is used only when the prop is undefined — a real value you pass always wins.
  • ✅ Values like "", 0, and false are real values, so they do NOT trigger the default.
  • ✅ The legacy Component.defaultProps does the same job but is being phased out; the destructuring default is preferred.
  • ✅ Defaults are most useful for optional props and reusable UI components like buttons and cards.

Check Your Knowledge

Test what you learned. Pick an answer for each question, then click Check.

  1. 1

    What value does a prop have when it is not passed to a component?

    Why: If you do not pass a prop, React simply gives you `undefined` for it. No error is thrown — the component still renders, which is exactly why a default value is useful.

  2. 2

    What is the modern, preferred way to set a default value for a prop in a function component?

    Why: Setting the default right in the destructuring keeps the fallback next to the prop and is the recommended modern approach. `defaultProps` still works but is being phased out for function components.

  3. 3

    When you write { color = 'blue' } and a parent passes color='', what color is used?

    Why: A destructuring default only replaces `undefined`. An empty string is a real value, so it is kept and the default does NOT take over. The same is true for `0` and `false`.

  4. 4

    Why are default props especially helpful for reusable UI components?

    Why: Reusable components like buttons and cards get used in many places, and people often skip optional props. A default gives a safe fallback so the component never renders empty or broken.

🚀 What’s Next?

Now your components are safe even when props go missing. Next we will look at a special prop that lets you pass whole pieces of UI between a component’s tags, so you can build flexible wrappers and layouts.

React Children Props

Share & Connect