DEV Community

Boluwatife Adeyeye
Boluwatife Adeyeye

Posted on • Edited on

Building My First Reusable Component: A Guide to React Props

When I started cloning websites like YouTube and Twitter, I hit a frustrating wall. I found myself copy-pasting the same HTML button structure seven times across different pages, just to change the label from 'Subscribe' to 'Post'. I remember groaning, "Not again."

Then, during a ReactJS class, I discovered the solution: Props.

By the end of this article, you will be able to stop rewriting code. You will learn to create reusable component "templates" and simply inject the data you need later.

The Pain of Hardcoding (The "Wrong" Way)

If you're new to React, your first instinct is usually to shove everything inside the component. I did this for weeks. It looks something like this:

function Button() {
  // ❌ The text is hardcoded inside
  return (
    <button className="btn-primary">
      Click Me
    </button>
  );
}

export default function App() {
  return (
    <div>
      <Button />
      <Button />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

The Problem starts here: This isn't reusable. Every time you use <Button />, it will always render "Click Me." If you need a button that says "Submit" and another that says "Cancel," you would be forced to copy-paste code and create entirely new components like <SubmitButton /> and <CancelButton />. This makes the codebase a total nightmare to fix.

The Solution: Passing Data "Down"

Instead of hardcoding the text, we should pass the text into the component when we call it. This allows a single component to be reused for different purposes.

Here is how you call the component from the Parent to make it dynamic:

export default function App() {
  return (
    <div>
      {/* ✅ We pass data "down" to the child via attributes */}
      <Button label="Submit" />
      <Button label="Cancel" />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Now, the parent component controls what the button says, making the Button component truly reusable.

Reading the Props

Now that we have passed the data into the component, we need to catch it on the other side.

1. The "Standard" Way (The Props Object)

When you write <Button label="Submit" />, React takes all the attributes you wrote (like label, color, size) and bundles them into a single JavaScript object. By convention, we call this object props.

Here is how the Button component looks when it receives that object:

// 1. We accept the entire "props" object as an argument
function Button(props) {
  return (
    // 2. We access the specific data using dot notation
    <button className="btn-primary">
      {props.label}
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

How it works:
React automatically passes an object that looks like this: { label: "Submit" }. We have to type props. every time we want to access a value.

2. Destructuring (My Personal Favorite)

While props.label works, it gets tedious. If you had five different props, you would end up repeating the word "props" five times (props.title, props.image, props.date, etc.).

Modern React developers use Destructuring. This allows us to "unpack" the values we need right inside the function parentheses.

// 1. We unpack "label" directly. No "props" variable needed!
function Button({ label }) {
  return (
    // 2. Now we can use the variable directly
    <button className="btn-primary">
      {label}
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

The Final Boss (children)

We have mastered passing data like strings and numbers. But what if we want to pass structure?

The Limitation of Standard Props

Standard props are perfect for small pieces of data. But imagine you are building a generic Card container. If you only used standard props, you would have to shove all your HTML into a string.

The Messy Way (Don't do this):

// ❌ Passing HTML as a string is ugly and hard to read
<Card 
  content="<h1>Title</h1><p>Here is some text</p><button>Click me</button>" 
/>
Enter fullscreen mode Exit fullscreen mode

This is rigid. What if you want an image in one card, but a video in another? You can't predict every possible layout.

The Solution: The children Prop

React gives us a special, "magic" prop called children. This allows us to use our custom component just like a regular HTML tag (like a <div>). We can nest whatever we want between the opening and closing tags.

The "Wrapper" Way (Parent):

export default function App() {
  return (
    <div className="layout">
      {/* ✅ We nest content INSIDE the component tags */}
      <Card>
        <h2>My Profile</h2>
        <p>I am a software engineer.</p>
        <button>Contact Me</button>
      </Card>

      <Card>
        <h2>Photo Gallery</h2>
        <img src="vacation.jpg" alt="Vacation" />
      </Card>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

This is incredibly powerful. The Card component doesn't care what is inside it. It just provides the box; you provide the content.

The Implementation (Component)

So, how does the Card know where to put that content? We capture it using the children prop.

// 1. Destructure the special "children" prop
function Card({ children }) {
  return (
    <div className="card-styles">
      {/* 2. Determine WHERE the nested content should appear */}
      {children}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Whatever you put between <Card> and </Card> automatically lands right where you wrote {children}.

Conclusion: Stop Repeating Yourself

You have officially graduated from rigid, copy-pasted code to building flexible, reusable systems. We covered the evolution of a React component: avoiding hardcoded text, passing dynamic data via Props, and finally, wrapping complex layouts using the powerful children prop.

Your Challenge:
Don’t let this knowledge sit idle. Open your current project right now and look for any UI elements you’ve written twice. Pick one, turn it into a reusable component, and see how much cleaner your code becomes.

Top comments (0)