Skip to main content

Components and Props

Composing Components

Written by Published

An interface is a tree of small components. The skill is not writing them - it is deciding where one ends and the next begins.

Nesting is the whole mechanism

A component uses other components exactly as it uses HTML tags. There is no registration step and no import list beyond ordinary JavaScript - if the function is in scope, you can render it.

A tree three levels deep

jsx

function Badge({ text }) {
  return (
    <span style={{ background: "#e2e8f0", padding: "2px 8px", borderRadius: 999 }}>
      {text}
    </span>
  )
}

function CardHeader() {
  return (
    <div style={{ display: "flex", gap: 8, alignItems: "center" }}>
      <strong>Ada Lovelace</strong>
      <Badge text="Admin" />
    </div>
  )
}

function Card() {
  return (
    <div style={{ border: "1px solid #cbd5e1", borderRadius: 10, padding: 14 }}>
      <CardHeader />
      <p style={{ margin: "8px 0 0", color: "#475569" }}>Wrote the first algorithm.</p>
    </div>
  )
}

const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(<Card />)

Card does not know what a badge looks like. If the badge changes colour, only Badge is edited - and every card in the app follows.

When to split one out

The instinct to split early is usually wrong. A hundred-line component that is read top to bottom is easier to work with than six files you have to jump between.

  1. You are about to repeat the same markup a second time.
  2. A section has grown its own logic and you can name it precisely.
  3. You want to reuse it somewhere unrelated.
  4. The function no longer fits on a screen and the parts are genuinely independent.

"It is long" alone is not a reason. Splitting for length produces components named CardPartTwo, which nobody can find later.

Naming tells you if the split is right

If a clear name comes immediately - Avatar, PriceTag, EmptyState - the boundary is probably real. If the best you can manage is Wrapper or Section, the split is arbitrary and you are moving code rather than organising it.

Where components live

  • One exported component per file, named after the file.
  • A small helper used only by that file can sit in the same file, below the main one.
  • Group by feature rather than by type - a folder per feature beats a folder of every component in the app.

None of this is enforced by React. It has no opinion about files at all, which is why every team's structure differs and why the rules above are conventions rather than requirements.