Lesson 3 of 12

React Components

React components are the heart of every React app. A component is a JavaScript function that returns JSX, and you can use it like a custom HTML tag as often as you like. In this lesson you will create components, put them inside each other and learn the few rules that keep them predictable. You already know the syntax from React JSX; now you will organise it.

Creating a component

A function component has three parts: a name that starts with a capital letter, a function body, and a return with JSX. Once it exists, you use it as a tag: <Greeting />.

function Greeting() {
  return <p>Good morning from Madurai!</p>;
}

// Using it inside another component
function App() {
  return (
    <div>
      <Greeting />
      <Greeting />
    </div>
  );
}

The capital letter is not just a style choice. JSX treats lowercase tags such as <section> as HTML elements and capitalised tags such as <Greeting /> as components. If you name your function greeting, React will try to create an unknown HTML element called greeting and your component will never run.

Nesting components: the component tree

Components can render other components, which can render more components. The result is a tree, with App at the top. This lets you think about one small piece at a time. A restaurant page might be an App containing a Header, a Menu and a Footer, and the Menu might contain several Dish components.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>A page made of components</title>
  <script src="https://unpkg.com/@babel/[email protected]/babel.min.js"></script>
  <style>
    body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
    .site-header { background: #0b6e99; color: #fff; padding: 8px 16px; border-radius: 8px; }
    .menu { display: flex; gap: 12px; flex-wrap: wrap; }
    .dish { border: 1px solid #ddd; border-radius: 8px; padding: 8px 12px; min-width: 140px; }
    footer { margin-top: 16px; color: #666; font-size: 14px; }
  </style>
</head>
<body>
  <div id="root"></div>

  <script type="text/babel" data-type="module">
import React from "https://esm.sh/[email protected]";
import { createRoot } from "https://esm.sh/[email protected]/client";

function Header() {
  return (
    <header className="site-header">
      <h1>Annapoorna Mess</h1>
      <p>Home-style South Indian meals</p>
    </header>
  );
}

function Dish() {
  return (
    <div className="dish">
      <strong>Mini tiffin</strong>
      <p>Idli, dosa, pongal and kesari</p>
    </div>
  );
}

function Menu() {
  return (
    <section>
      <h2>Today's specials</h2>
      <div className="menu">
        <Dish />
        <Dish />
        <Dish />
      </div>
    </section>
  );
}

function Footer() {
  const year = new Date().getFullYear();
  return <footer>Open 7 am to 10 pm · © {year}</footer>;
}

function App() {
  return (
    <>
      <Header />
      <Menu />
      <Footer />
    </>
  );
}

createRoot(document.getElementById("root")).render(<App />);
  </script>
</body>
</html>

Right now every Dish shows the same text. That is fine for practice, but real components need to show different data each time. The next lesson, React Props, solves exactly that.

Watch out: Always define components at the top level of your file, never inside another component. A component defined inside another one is created afresh on every render, so React treats it as a brand-new component each time. It throws away its state and its DOM, which causes lost input text and slow pages.

Keep components pure

React expects components to behave like pure functions: given the same inputs, they return the same JSX, and they do not change anything outside themselves while rendering. React may call your component many times – whenever data changes, and in development sometimes twice on purpose to catch mistakes – so a component that changes outside variables during rendering gives different results each time.

// Impure: changes a variable outside the component while rendering
let guestCount = 0;
function Guest() {
  guestCount = guestCount + 1;
  return <p>Guest number {guestCount}</p>;
}

// Pure: the output depends only on what is passed in
function Guest({ number }) {
  return <p>Guest number {number}</p>;
}

Reading values that do not change, like a list of menu items declared at the top of the file, is fine. Changing things – updating the DOM by hand, starting a timer, sending a request – belongs in event handlers or effects, which you will meet in later lessons.

Rendering nothing

Sometimes a component should not show anything. In that case, return null. React renders nothing for null, undefined, true and false. You will use this a lot in Conditional Rendering.

How to split a page into React components

Beginners often ask how big a component should be. There is no fixed rule, but these signals help:

  • A piece of UI is repeated – cards, list rows, buttons – so make it a component.
  • A piece has a clear name and job, like SearchBar or PriceTag.
  • A component has grown so long that you scroll to understand it. Split it into smaller ones.
  • If you work from a Figma design, the designer’s components are a good first guide to your React components.

In a real project, each important component usually lives in its own file and is shared with export and import. Our in-browser examples keep everything in one script, but you will use separate files in React Project with Vite. File names normally match the component name.

// Header.jsx
export default function Header() {
  return <header><h1>Annapoorna Mess</h1></header>;
}

// App.jsx
import Header from "./Header.jsx";

export default function App() {
  return <Header />;
}

Tip: You may see components written as arrow functions: const Header = () => <header>…</header>;. That works exactly the same. Pick one style and stay consistent within a project.

Further reading

Key takeaways

  • A component is a function that returns JSX; use it like a tag: <Header />.
  • Component names must start with a capital letter.
  • Components nest inside each other to form a tree with App at the top.
  • Define components at the top level, never inside another component.
  • Keep components pure: same inputs, same output, no outside changes during render.
  • Return null to render nothing.

Quick quiz

Check what you learned – pick an answer.

1. Why must a component name start with a capital letter?

2. What should a component return to show nothing at all?

3. Which of these breaks the "keep components pure" rule?

Practice exercise

Create three components – Logo, NavLinks and PageHeader. PageHeader should render Logo and NavLinks side by side. NavLinks shows three links: Home, Courses and Contact. Render PageHeader from App.

Show a hint

Use a flex container with className in PageHeader. Links can point to "#" for now.

Show the solution
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Page header</title>
  <script src="https://unpkg.com/@babel/[email protected]/babel.min.js"></script>
  <style>
    body { font-family: system-ui, sans-serif; padding: 16px; line-height: 1.5; }
    header { display: flex; justify-content: space-between; align-items: center; gap: 16px; }
    nav { display: flex; gap: 12px; }
  </style>
</head>
<body>
  <div id="root"></div>

  <script type="text/babel" data-type="module">
import React from "https://esm.sh/[email protected]";
import { createRoot } from "https://esm.sh/[email protected]/client";

function Logo() {
  return <strong>Code Kalvi</strong>;
}

function NavLinks() {
  return (
    <nav>
      <a href="#">Home</a>
      <a href="#">Courses</a>
      <a href="#">Contact</a>
    </nav>
  );
}

function PageHeader() {
  return (
    <header>
      <Logo />
      <NavLinks />
    </header>
  );
}

function App() {
  return <PageHeader />;
}

createRoot(document.getElementById("root")).render(<App />);
  </script>
</body>
</html>

Progress is saved in this browser only.