Skip to content
React rc components 4 min read

Components & Props

Components are the building blocks of every React application. A component is a JavaScript function that returns JSX describing a piece of UI, and props are the inputs you pass to configure it. Together they let you split an interface into small, independent, reusable pieces that you can reason about and test in isolation. Mastering how props flow into components — and the rule that they are read-only — is the foundation for everything else in React.

Function components

A modern React component is simply a function whose name starts with a capital letter and that returns JSX (or null). The capital letter is what tells React (and JSX) to treat it as a component rather than a built-in HTML element like div.

function Greeting() {
  return <h1>Hello, React!</h1>;
}

export default Greeting;

You render a component by using it as a tag. React then calls your function and inserts whatever it returns into the DOM.

import { createRoot } from "react-dom/client";
import Greeting from "./Greeting.jsx";

createRoot(document.getElementById("root")).render(<Greeting />);

Output:

Hello, React!

Passing and reading props

Hard-coded UI is rarely useful. To make a component configurable, you pass props as attributes on the JSX tag. React collects them into a single object and hands it to your function as the first argument.

function Greeting(props) {
  return <h1>Hello, {props.name}!</h1>;
}

function App() {
  return (
    <div>
      <Greeting name="Ada" />
      <Greeting name="Linus" />
    </div>
  );
}

Output:

Hello, Ada!
Hello, Linus!

The same component renders different output for each call because each receives a different props.name. Any JavaScript value can be passed — but anything other than a string literal must go inside curly braces:

<Profile name="Grace" age={37} isAdmin={true} tags={["react", "js"]} />

Props are read-only

The single most important rule about props is that a component must never modify its own props. Props flow in one direction only: from parent to child. A component receives data, reads it, and renders — it does not change the data it was given. This one-way data flow is what makes React apps predictable; you can always trace where a value came from.

function Counter(props) {
  // ❌ Never do this — props are read-only
  // props.count = props.count + 1;

  return <p>Count: {props.count}</p>;
}

If a value needs to change over time in response to user interaction, that is state, not props. Props are the configuration passed down; state is data owned and managed inside a component.

Treating components as pure functions of their props — same props in, same UI out — keeps rendering reliable and makes components easy to test.

Destructuring props

Reading props.something repeatedly is noisy. Most React code destructures props directly in the function signature, which doubles as a clear list of the inputs a component expects.

function Profile({ name, age, isAdmin }) {
  return (
    <section>
      <h2>{name}</h2>
      <p>Age: {age}</p>
      {isAdmin && <span>Administrator</span>}
    </section>
  );
}

This is purely a syntax convenience — { name, age } pulls those keys out of the props object. It behaves identically to accessing props.name and props.age.

Passing functions, objects, and JSX

Props are not limited to strings and numbers. Because curly braces accept any JavaScript expression, you can pass objects, arrays, functions, and even other elements.

Passing a function is how a child communicates back up to its parent — for example, to notify it of a click:

function Button({ label, onClick }) {
  return <button onClick={onClick}>{label}</button>;
}

function Toolbar() {
  const handleSave = () => console.log("Saved!");
  return <Button label="Save" onClick={handleSave} />;
}

Output (after click):

Saved!

You can also pass an object and let the child read its fields, or pass JSX as a prop when a component needs configurable content in a specific slot:

function Card({ user, header }) {
  return (
    <article>
      {header}
      <p>{user.name}{user.email}</p>
    </article>
  );
}

function App() {
  const user = { name: "Ada", email: "[email protected]" };
  return <Card user={user} header={<h3>User Profile</h3>} />;
}

The special children prop covers the most common case of passing JSX between a component’s opening and closing tags — see the related page on composition for that pattern.

Composing components

The real power of components is composition: building larger UIs by nesting smaller components inside one another. Each component stays focused on one responsibility, and parents wire them together by passing props down.

function Avatar({ url, alt }) {
  return <img className="avatar" src={url} alt={alt} />;
}

function UserBadge({ user }) {
  return (
    <div className="badge">
      <Avatar url={user.avatarUrl} alt={user.name} />
      <strong>{user.name}</strong>
    </div>
  );
}

Here UserBadge composes Avatar, forwarding the data each child needs. Because every component is independent, you can reuse Avatar anywhere an image is required.

The table below summarizes the core terms:

TermWhat it isDirection
ComponentFunction returning JSX
PropsInputs passed by the parentParent → child (read-only)
StateData owned inside a componentLocal, mutable via setters
CompositionNesting components togetherParent renders children

Best Practices

  • Name components with PascalCase so JSX treats them as components, not HTML tags.
  • Keep components small and focused on a single responsibility, then compose them.
  • Never mutate props — derive new values or lift changing data into state.
  • Destructure props in the signature to document a component’s expected inputs.
  • Pass callbacks down as props so children can report events back to parents.
  • Prefer many simple presentational components over one large monolithic one.
  • Give props clear, descriptive names that reflect their meaning, not their type.
Last updated June 14, 2026
Was this helpful?