Skip to content

JSX and Component Rendering

JSX is syntax for describing a tree of elements inside JavaScript. It resembles HTML, but a browser does not execute JSX directly. A build transform converts it into JavaScript calls understood by a UI library.

jsx
function Greeting({ name }) {
  return <h1>Hello, {name}</h1>;
}

With a modern React transform, the result is conceptually similar to:

js
function Greeting({ name }) {
  return jsx("h1", { children: ["Hello, ", name] });
}

The exact helper is an implementation detail. The essential point is that <h1> produces a JavaScript description, not a DOM node. React later reconciles that description with a renderer such as the browser DOM.

TSX is JSX in a TypeScript file. It adds checking of component props, intrinsic elements, and expressions; it does not change React's runtime behavior.

Markup and JavaScript expressions coexist

Curly braces enter JavaScript expression mode:

jsx
function Transaction({ transaction }) {
  return (
    <article className={transaction.settled ? "settled" : "pending"}>
      <h2>{transaction.description}</h2>
      <p>{formatCurrency(transaction.amount)}</p>
    </article>
  );
}

JSX attributes use JavaScript-oriented names for some DOM properties: className, htmlFor, and camel-cased event handlers such as onClick. Most attributes closely resemble HTML, but JSX follows the library's property model rather than being pasted HTML.

JSX expressions must produce one enclosing value. A fragment groups siblings without adding a DOM wrapper:

jsx
return (
  <>
    <Header />
    <TransactionList />
  </>
);

Lowercase tags describe host elements such as div; capitalized names refer to variables, normally components:

jsx
const heading = <h1>Report</h1>;
const page = <ReportPage report={report} />;

Components are ordinary JavaScript functions by convention, but React controls when they are called. Call them with JSX rather than ReportPage({ report }), so hooks and component identity remain under React's rules.

Rendering collections requires identity

jsx
function TransactionList({ transactions }) {
  return (
    <ul>
      {transactions.map(transaction => (
        <li key={transaction.id}>
          {transaction.description}
        </li>
      ))}
    </ul>
  );
}

key helps React associate an element with the same logical item across insertions, removals, and reordering. It is consumed by React and is not passed as an ordinary prop. Use a stable identity from the data. An array index is safe only when item identity truly follows position and the list does not reorder or change shape.

Conditional rendering is JavaScript

jsx
function ReportBody({ state }) {
  if (state.status === "loading") return <Spinner />;
  if (state.status === "failure") return <ErrorMessage error={state.error} />;

  return state.transactions.length === 0
    ? <EmptyState />
    : <TransactionList transactions={state.transactions} />;
}

Inside JSX, short-circuiting is common:

jsx
{isAdmin && <AdminControls />}

Remember that && returns an operand. If the left value is 0, React can render 0:

jsx
{items.length > 0 && <List items={items} />}

Explicit booleans avoid accidental output.

Props are inputs; composition supplies structure

jsx
function Panel({ title, children }) {
  return (
    <section className="panel">
      <h2>{title}</h2>
      {children}
    </section>
  );
}

<Panel title="Summary">
  <ReportSummary report={report} />
</Panel>

children is an ordinary prop populated by nested JSX. Component composition often replaces inheritance: a parent supplies content or specialized components through props.

Keep components pure during rendering. Given the same props, state, and context, a render should calculate the same description without changing outside state:

jsx
// Bad: mutation during rendering
function Total({ transactions }) {
  analytics.record("total rendered");
  return <span>{calculateTotal(transactions)}</span>;
}

Rendering may be repeated, paused, or discarded. Event handlers and effects are the places for external interaction.

JSX escaping is helpful but not universal sanitization

React escapes string values inserted with braces, so user text is normally rendered as text:

jsx
<p>{comment.body}</p>

dangerouslySetInnerHTML bypasses that protection and should receive only trusted or correctly sanitized HTML. JSX also cannot make an unsafe URL, server request, or authorization decision safe; security depends on the specific sink and boundary.

Rendering is separate from component description

A browser entry point mounts a React tree into an existing DOM node:

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

const rootElement = document.querySelector("#root");
if (!rootElement) throw new Error("Missing #root element");

createRoot(rootElement).render(<App />);

React DOM is one renderer. Server rendering produces HTML; React Native targets native interfaces. JSX itself does not imply the DOM, React, state, or interactivity. It is a syntax layer whose meaning comes from the configured transform and runtime.

Further reference