Skip to main content

React Introduction

Your First Component

Written by Published

A component is a function that returns UI. There is no base class to extend and no configuration object - if it returns JSX and its name is capitalised, it is a component.

The rules

  • It is a function.
  • Its name starts with a capital letter. This is not style - it is how JSX tells your components apart from HTML tags.
  • It returns a single piece of JSX, or null for nothing.

Capitalisation matters

jsx

function Card() {
  return <div style={{ border: "1px solid #cbd5e1", padding: 12 }}>A real component</div>
}

// Lowercase: JSX treats this as an unknown HTML tag, not your function.
function card() {
  return <div>Never rendered as a component</div>
}

const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(
  <div>
    <Card />
    <p>The lowercase one is not used — JSX would look for a &lt;card&gt; element.</p>
  </div>
)

Nesting components

Components are used inside other components exactly like HTML elements. That is how an interface is built: small pieces composed into larger ones.

Composition

jsx

function Avatar() {
  return <span style={{ fontSize: 28 }}>🙂</span>
}

function Name() {
  return <strong>Ada Lovelace</strong>
}

function ProfileRow() {
  return (
    <div style={{ display: "flex", gap: 10, alignItems: "center" }}>
      <Avatar />
      <Name />
    </div>
  )
}

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

ProfileRow does not know what Avatar renders, and does not need to. Each piece can change without the others being touched.

Returning one thing

A component must return a single element. Two siblings at the top level is a syntax error, because a function cannot return two values.

This does not compile

jsx

function Broken() {
  return (
    <h2>Title</h2>
    <p>Body</p>
  )
}

Wrap them in a parent element, or in an empty <>...</> fragment when you do not want an extra div in the output.

Fragments

jsx

function Pair() {
  return (
    <>
      <h3>Title</h3>
      <p>Body, with no wrapper div added to the page.</p>
    </>
  )
}

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

Getting it on the page

One call mounts the whole tree. createRoot takes a DOM node React is allowed to control, and render hands it your top component. Every example on this site already has a #root div waiting.

React owns everything inside that node from then on. Do not also change it with innerHTML or appendChild - React will overwrite your edit the next time it renders, and the two will disagree in ways that are hard to trace.

One file, one component

A component can be any size, but the useful default is one exported component per file, named after the file. Avatar.jsx exports Avatar. Small helper components used only by that file can live alongside it.

The instinct to split early is usually wrong. Write it as one component, and pull a piece out when you find yourself repeating it or when the function gets hard to read - not before.

  • A component is a function returning JSX.
  • Capitalise the name or JSX will not recognise it.
  • Return one element; use a fragment when you do not want a wrapper.
  • Compose small components rather than writing one large one.