Overview

JSX compiles to function calls, so braces {} hold JavaScript expressions (never statements) and every tag must close. TSX is JSX in a .tsx file with TypeScript types. Hooks are on react-hooks.

Expressions

Put only expressions in braces; use early returns for statements.

PatternExample
Value, expression, call<p>{name}</p>, {count * 2}, {items.join(", ")}
String prop / expression prop<a href="/x">, <Button disabled={!ready} />
Spread props<Input {...props} />
Handler<button onClick={() => save(id)}>
Template literal<p>{`Hello, ${name}`}</p>
Attribute namesclassName, htmlFor, tabIndex, onClick

Conditional rendering

Prefer early returns over nested ternaries.

PatternSyntaxUse when
Ternary{ok ? <A /> : <B />}Two branches.
&&{count > 0 && <Badge />}Show or nothing; the left side must be a boolean.
??{value ?? <Fallback />}Fallback only for null or undefined.
Early returnif (!data) return <Spinner />;Loading and error guards; avoids nested ternaries.

Lists, keys, fragments

Use a stable id as the key, never an index in reorderable lists.

{items.map((i) => <Row key={i.id} item={i} />)}          // stable id, not the index
{items.map((i) => (
  <Fragment key={i.id}><dt>{i.term}</dt><dd>{i.def}</dd></Fragment>
))}
<>
  <Header />
  <Main />
</>                                                         // short form: no key, no props

Keys must be unique among siblings and stable between renders. An index is acceptable only for lists that never reorder. A composite key looks like key={`${group}-${i.id}`}.

Typing props, events, and refs

Type props with an interface and events with React.*Event types.

NeedTSX
Propsinterface Props { title: string; children?: React.ReactNode }
Extend a native elementtype Props = React.ComponentProps<"button"> & { busy?: boolean }
Change handler(e: React.ChangeEvent<HTMLInputElement>) => void
Click handler(e: React.MouseEvent<HTMLButtonElement>) => void
DOM refconst ref = useRef<HTMLDivElement>(null)
Generic componentfunction List<T>({ items }: { items: T[] }); in arrow functions write <T,>
Return typeReact.JSX.Element (the global JSX namespace is removed in React 19 types)

In React 19, ref is an ordinary prop on function components, so forwardRef is no longer needed for new code. Ref callbacks must use a block body so they return nothing: ref={(el) => { node.current = el }}.

Gotchas

Avoid these; each renders unexpected output or fails to parse.

GotchaFix
{count && <X />} renders 0 when count is 0.Compare: {count > 0 && <X />}.
<T> alone in a .tsx arrow function parses as JSX.Write <T,> or <T extends unknown>.
key is not readable as props.key.Pass the id as a separate prop.
<br> and <img> without a closing slash are errors.Self-close: <br />.
class and for are reserved words.Use className and htmlFor.
A random or Date.now() key remounts the item every render.Use a stable id.