JSX and Rendering

This section documents React 19.x for the web, using function components and Hooks throughout (class components appear only where React still requires them, such as error boundaries). React Native is out of scope and gets only a pointer. The React 19 additions follow the current official React documentation. This content was generated with the assistance of AI and should be verified against react.dev before being relied on in production, since React APIs continue to evolve between releases.

This section’s bibliography lists the reference material consulted while preparing these pages.

JSX is an XML-like syntax extension for JavaScript. A build tool (Vite, Babel, the TypeScript compiler) transforms it into React.createElement / jsx() calls that return plain objects describing the UI. You can write React without JSX, but nearly everyone uses it.

JSX basics

  • A component returns one root element. Wrap siblings in a parent element or an empty Fragment <>…​</> (import Fragment when you need to give it a key).

  • Attributes are camelCase and follow the DOM property names: className (not class), htmlFor (not for), onClick, tabIndex.

  • Every tag must be closed: <br />, <img src="…​" />.

  • JSX is an expression — you can store it in a variable, return it, or pass it as a prop.

function Card() {
  return (
    <>
      <h2 className="card-title">Title</h2>
      <img src="/logo.png" alt="" />
    </>
  );
}

Converting HTML to JSX is mostly mechanical: rename class/for, close void elements, camelCase event and style attributes, and wrap in a single parent. See Writing Markup with JSX.

Curly braces: JavaScript in JSX

Curly braces { } embed a JavaScript expression in JSX — in children or in an attribute value. A quoted string is a literal; braces are code.

const user = { name: 'Ada', theme: 'dark' };

<h1>{user.name}'s dashboard</h1>          // expression in children
<img src={user.avatarUrl} alt="" />       // expression as an attribute
<p title={`Signed in as ${user.name}`}>…</p>

"Double curlies" are just an object literal inside the braces — most often an inline style object (whose keys are camelCased CSS properties):

<div style={{ color: 'red', marginTop: 8 }}>Warning</div>

Only strings, numbers, and JSX render as children; true, false, null, and undefined render nothing. Objects do not render — <p>{user}</p> throws. See JavaScript in JSX with Curly Braces.

Conditional rendering

function Status({ user }) {
  if (!user) return null;                       // render nothing

  return (
    <div>
      {user.isAdmin ? <AdminBadge /> : <UserBadge />}   {/* ternary */}
      {user.messages.length > 0 && <Inbox count={user.messages.length} />}  {/* && */}
    </div>
  );
}

Beware {count && <Inbox />} when count is 0 — React renders the 0. Use count > 0 && … or Boolean(count) && …. See Conditional Rendering.

Rendering lists

Transform an array with .map() (and .filter()), returning one element per item. Each sibling needs a stable, unique key so React can match elements across renders.

function TodoList({ todos }) {
  return (
    <ul>
      {todos
        .filter((t) => !t.archived)
        .map((t) => (
          <li key={t.id}>{t.text}</li>
        ))}
    </ul>
  );
}

key must be unique among siblings and come from the data (a database id, a slug). Do not use the array index as a key when the list can reorder, filter, or grow at the front: React would keep state attached to the wrong item. key is a hint to React, not a prop your component can read. See Rendering Lists.

Rendering into the page

createRoot from react-dom/client connects a React tree to a real DOM node. Call root.render once with your top component; later state changes re-render through the same root.

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';

const root = createRoot(document.getElementById('root'));
root.render(
  <StrictMode>
    <App />
  </StrictMode>
);

In development, <StrictMode> intentionally double-invokes component functions and Effect setup/cleanup to help you catch impure renders and missing cleanup; this does not happen in production. For server-rendered HTML you call hydrateRoot instead — see Server Rendering. For the underlying DOM API that createRoot drives, see Web Programming Basics.