Welcome back, aspiring React developer! In the previous chapters, you set up your development environment and explored some fundamental JavaScript concepts that power modern React. Now, it’s time to dive into the very heart of React: Components. Think of components as the Lego bricks of your user interface – small, self-contained, and reusable pieces that you can snap together to build complex and dynamic applications.

In this chapter, we’ll unravel what components are, why they’re so powerful, and how they allow us to structure our applications in a clean and maintainable way. You’ll learn about JSX, React’s special syntax for describing UI, and how to pass data between components using something called “props.” By the end of this chapter, you’ll be confidently creating and combining your own React components, laying a solid foundation for everything that comes next. Get ready to build!

What are Components? The Lego Bricks of Your UI

Imagine you’re building a house. You wouldn’t build it from scratch every time, right? You’d use pre-made bricks, windows, and doors. In React, components are exactly like those pre-made pieces. They are independent, reusable bits of code that return React elements, describing what should appear on the screen.

The modern way to write components in React is using functional components. These are just plain JavaScript functions that take an object of “props” (we’ll get to those soon!) as an argument and return JSX. While you might encounter “class components” in older codebases, functional components with Hooks (which we’ll cover in a later chapter) are the recommended approach for new React development as of 2026.

Let’s look at a simple mental model:

graph TD A[Your App] --> B[Header Component] A --> C[Sidebar Component] A --> D[Main Content Component] D --> E[Card Component 1] D --> F[Card Component 2] E --> G[Image Component] E --> H[Text Component]

In this diagram, Your App is composed of Header, Sidebar, and Main Content. The Main Content itself might be composed of Card components, which in turn use Image and Text components. Each box represents a component, a self-contained piece of UI logic.

JSX: Blending JavaScript with UI Descriptions

You might have heard of JSX. It stands for JavaScript XML and it’s a syntax extension for JavaScript that allows you to write HTML-like code directly within your JavaScript files.

Why JSX? It might seem a bit odd at first, mixing HTML with JavaScript. But JSX makes your UI code more intuitive and easier to understand. Instead of calling React.createElement() functions repeatedly (which is what JSX transpiles into under the hood), you can write familiar tag syntax. It allows you to describe your UI’s structure and behavior in a single, cohesive place.

How JSX Works (The Core Rules):

  1. Single Root Element: Every JSX block must return a single root element. You can’t return two sibling elements without wrapping them. If you don’t want an extra div, you can use a Fragment (<></> or <React.Fragment></React.Fragment>).
  2. CamelCase for Attributes: HTML attributes like class become className in JSX, and for becomes htmlFor. This is because class and for are reserved keywords in JavaScript.
  3. JavaScript Expressions in Curly Braces {}: To embed JavaScript variables, expressions, or function calls directly into your JSX, you wrap them in curly braces {}.
  4. Self-Closing Tags: If an element has no children (like an <img> or <input>), it must be self-closing: <img /> or <input />.
  5. Case Sensitivity: React component names must start with an uppercase letter (<MyComponent />), while standard HTML elements start with lowercase (<div>). This helps React differentiate between your custom components and built-in browser elements.

Let’s ponder for a moment: How does <div>Hello</div> become JavaScript? It’s transformed by a build tool (like Babel, which Vite uses) into something like React.createElement('div', null, 'Hello'). JSX is just syntactic sugar!

Props: Passing Data to Components

Components are great, but they’d be pretty static if they couldn’t receive data. That’s where props (short for “properties”) come in. Props are how you pass data from a parent component down to a child component. Think of them like arguments to a function.

Key characteristics of props:

  • Read-only: A child component should never modify its own props. Props are meant to be passed down and used as they are. If a component needs to change data, it should manage its own “state” (which we’ll learn about next!).
  • Arbitrary Data: You can pass any JavaScript data type as a prop: strings, numbers, booleans, arrays, objects, and even functions.

Consider our Greeting component from the diagram. If we want it to greet different people, we’d pass the name as a prop!

Step-by-Step Implementation: Building Our First Components

Let’s get our hands dirty! We’ll start with a clean slate, assuming you have a basic Vite-React project set up from Chapter 2.

1. Create a New Component File

First, let’s create a dedicated folder for our components. In your project’s src directory, create a new folder called components. Inside components, create a file named Greeting.jsx.

# Assuming you are in your project's root directory
mkdir src/components
touch src/components/Greeting.jsx

Now, open src/components/Greeting.jsx and add the following code:

// src/components/Greeting.jsx
import React from 'react'; // Not strictly necessary for JSX in modern React, but good practice.

// This is our first functional component!
function Greeting() {
  return (
    // JSX looks a lot like HTML, doesn't it?
    <div>
      <h2>Hello, React Learner!</h2>
      <p>This is your first custom component.</p>
    </div>
  );
}

// We need to export our component so other files can use it.
export default Greeting;

Explanation:

  • import React from 'react';: While not strictly required for JSX transformation in modern React (since React 17’s new JSX transform), it’s a widely adopted convention and doesn’t hurt. For older versions or specific setups, it might still be necessary.
  • function Greeting() { ... }: This defines a simple JavaScript function named Greeting. This function is our component.
  • return (...): Inside the function, we return JSX. Notice it’s wrapped in parentheses. This is a common practice when your JSX spans multiple lines to ensure JavaScript’s automatic semicolon insertion doesn’t break your code.
  • <div>...</div>: Our component returns a single div element, which is the root element for this piece of JSX.
  • export default Greeting;: This makes our Greeting component available for other files to import and use. export default is used when you want to export only one thing from a module.

2. Using Your First Component in App.jsx

Now, let’s bring our Greeting component into our main App.jsx file.

Open src/App.jsx and modify it to look like this:

// src/App.jsx
import './App.css'; // Keep your styles
import Greeting from './components/Greeting.jsx'; // 👈 Import our new component!

function App() {
  return (
    <div className="App">
      <h1>Welcome to My Awesome React App!</h1>
      {/* 👈 Now, we use our Greeting component like an HTML tag! */}
      <Greeting />
      <p>Isn't this component-based development fun?</p>
    </div>
  );
}

export default App;

Explanation:

  • import Greeting from './components/Greeting.jsx';: We import the Greeting component we just created. The path is relative to the current App.jsx file.
  • <Greeting />: We use our component! Notice it looks just like an HTML tag, but with an uppercase first letter. This is how React knows it’s a custom component and not a standard HTML element. Since Greeting doesn’t have any children, it’s a self-closing tag.

Save both files and check your browser. You should now see “Hello, React Learner!” and “This is your first custom component.” rendered on the page, coming directly from your Greeting component!

3. Passing Data with Props

Our Greeting component is a bit rigid, always saying “Hello, React Learner!”. Let’s make it more flexible by passing a name using props.

First, modify src/components/Greeting.jsx:

// src/components/Greeting.jsx
import React from 'react';

// We update our function to accept 'props' as an argument.
// A common pattern is to immediately destructure the props object.
function Greeting({ name = 'Guest', message = 'Welcome' }) { // 👈 Destructure 'name' and provide a default
  return (
    <div>
      {/* Now we use the 'name' prop inside our JSX! */}
      <h2>{message}, {name}!</h2> {/* 👈 Use message and name */}
      <p>This is a personalized greeting from your component.</p>
    </div>
  );
}

export default Greeting;

Explanation:

  • function Greeting({ name = 'Guest', message = 'Welcome' }): Instead of just props, we’re using object destructuring in the function parameters to directly get name and message. We also added default values ('Guest' and 'Welcome') in case the parent doesn’t pass these props. This is a modern JavaScript feature and a very common pattern in React.
  • {name} and {message}: We use curly braces to embed the JavaScript variables name and message directly into our JSX.

Next, let’s pass the name and message props from src/App.jsx:

// src/App.jsx
import './App.css';
import Greeting from './components/Greeting.jsx';

function App() {
  return (
    <div className="App">
      <h1>Welcome to My Awesome React App!</h1>
      {/* 👈 Pass props like HTML attributes */}
      <Greeting name="Alice" message="Greetings" />
      <Greeting name="Bob" /> {/* Bob will use the default message */}
      <Greeting /> {/* This one will use both default name and message */}
      <p>Isn't this component-based development fun?</p>
    </div>
  );
}

export default App;

Explanation:

  • <Greeting name="Alice" message="Greetings" />: We pass name and message as attributes to our Greeting component. React collects these attributes into an object and passes it as the props argument to the Greeting function.
  • <Greeting name="Bob" />: Here, we only pass name. Since message has a default value in Greeting.jsx, it will use “Welcome”.
  • <Greeting />: With no props passed, both name and message will fall back to their default values.

Observe your browser again. You should now see three different greetings, each customized by the props you passed! How cool is that?

4. The children Prop

Sometimes you want to wrap content with a component, much like how a <div> wraps text or other HTML elements. React has a special prop called children for this.

Let’s create a Card component that can wrap any content.

Create a new file src/components/Card.jsx:

// src/components/Card.jsx
import React from 'react';
import './Card.css'; // We'll add some basic styling for our card

function Card({ title, children }) { // 👈 Destructure 'title' and 'children'
  return (
    <div className="card">
      {title && <h3 className="card-title">{title}</h3>} {/* Only show title if it exists */}
      <div className="card-content">
        {children} {/* 👈 This is where the wrapped content will appear */}
      </div>
    </div>
  );
}

export default Card;

Now, let’s add some minimal styling for our card. Create src/components/Card.css:

/* src/components/Card.css */
.card {
  border: 1px solid #ddd;
  border-radius: 8px;
  padding: 16px;
  margin: 16px;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
  background-color: white;
  max-width: 300px;
  display: inline-block; /* For side-by-side cards */
  vertical-align: top;
}

.card-title {
  color: #333;
  margin-top: 0;
  margin-bottom: 10px;
}

.card-content {
  color: #555;
  font-size: 0.9em;
}

Finally, use the Card component in src/App.jsx:

// src/App.jsx
import './App.css';
import Greeting from './components/Greeting.jsx';
import Card from './components/Card.jsx'; // 👈 Import our Card component

function App() {
  return (
    <div className="App">
      <h1>Welcome to My Awesome React App!</h1>

      <Greeting name="Alice" message="Greetings" />
      <Greeting name="Bob" />
      <Greeting />

      {/* 👈 Now, let's use our Card component */}
      <Card title="My First Card">
        {/* Everything inside the <Card> tags becomes the 'children' prop */}
        <p>This is some content inside the card.</p>
        <strong>It can even contain other HTML elements!</strong>
      </Card>

      <Card title="Another Card">
        <ul>
          <li>Item 1</li>
          <li>Item 2</li>
          <li>Item 3</li>
        </ul>
      </Card>

      <Card>
        <p>This card has no title, just content.</p>
      </Card>

    </div>
  );
}

export default App;

Explanation:

  • <Card title="My First Card"> ... </Card>: The text and HTML elements placed between the opening and closing <Card> tags are automatically collected by React and passed to the Card component via a special prop named children.
  • {title && <h3 className="card-title">{title}</h3>}: This is a common pattern for conditional rendering. If title exists (is not null, undefined, false, or an empty string), then the <h3> element will be rendered. Otherwise, nothing will be rendered for the title.
  • <div className="card-content">{children}</div>: Inside the Card component, we render the children prop wherever we want the wrapped content to appear.

Refresh your browser, and you’ll see your components beautifully organized within cards! This demonstrates the power of composition and reusability.

Mini-Challenge: Build a UserAvatar Component

It’s your turn! Create a new component called UserAvatar.

Challenge:

  1. Create a file src/components/UserAvatar.jsx.
  2. This component should accept two props: imageUrl (a string for the avatar image source) and username (a string for the user’s name).
  3. It should display an <img> tag with the imageUrl as its src and the username as its alt text.
  4. Below the image, display the username in a <span> tag.
  5. Add some basic inline styling to the image (e.g., width: 50px, height: 50px, borderRadius: '50%') directly in the JSX using the style prop (remember it takes an object!).
  6. Import and use your UserAvatar component in App.jsx, passing different imageUrl and username values.

Hint:

  • Remember to use {} for JavaScript expressions, including the style prop which takes a JavaScript object.
  • Don’t forget to export default your component and import it in App.jsx.

What to Observe/Learn:

  • How to pass and use multiple props.
  • Applying inline styles in React JSX.
  • Further practice with component composition.

Common Pitfalls & Troubleshooting

  1. “Adjacent JSX elements must be wrapped in an enclosing tag”:

    • Problem: You tried to return multiple elements from a component’s return statement without wrapping them in a single parent element.
    • Example:
      function BadComponent() {
        return (
          <p>Hello</p>
          <p>World</p> // ❌ Error!
        );
      }
      
    • Solution: Wrap them in a <div> or a Fragment (<></>).
      function GoodComponent() {
        return (
          <> {/* Or <div> */}
            <p>Hello</p>
            <p>World</p>
          </> {/* Or </div> */}
        );
      }
      
  2. Trying to Modify Props:

    • Problem: You attempted to change the value of a prop directly within the child component.
    • Example:
      function MyComponent({ value }) {
        value = 'new value'; // ❌ Don't do this! Props are read-only.
        return <p>{value}</p>;
      }
      
    • Explanation: Props are meant to be immutable within the component that receives them. If a component needs to manage data that can change, it should use state (our next chapter’s topic!). If a parent needs to update a child’s display, it should pass new props from the parent.
  3. Missing Component Import:

    • Problem: You used a component in your JSX (e.g., <MyComponent />) but forgot to import it at the top of the file.
    • Error Message: Often something like “MyComponent is not defined” or “MyComponent is not a function”.
    • Solution: Always remember to add import MyComponent from './path/to/MyComponent'; at the top of any file where you use MyComponent.

Summary

Phew! You’ve just mastered the fundamental building blocks of React applications:

  • Components are reusable, self-contained pieces of UI, typically written as functional components in modern React.
  • JSX is React’s special syntax that lets you write HTML-like code directly within your JavaScript, making UI description intuitive. Remember its key rules like single root element, camelCase attributes, and {} for JavaScript expressions.
  • Props are how data flows from parent components to child components, enabling dynamic and reusable UIs. They are read-only within the child component.
  • The special children prop allows components to wrap and render arbitrary content passed between their opening and closing tags.

You’re now equipped to start seeing your entire application as a tree of interconnected components, each responsible for a small, focused part of the user interface. This component-based mental model is crucial for building scalable and maintainable React apps.

What’s Next? While props are great for passing static data or data that changes only in the parent, what if a component needs to manage its own internal data that can change over time? That’s where state comes in! In Chapter 4, we’ll introduce the useState Hook and unlock the ability for your components to be dynamic and interactive. Get ready for even more power!

References

This page is AI-assisted and reviewed. It references official documentation and recognized resources where relevant.