Overview

JSX is syntactic sugar for React.createElement calls; TSX is JSX with TypeScript’s type system on top. Understanding the desugared form explains most of the edge cases around keys, fragments, and conditional rendering. This card is a quick reference for the patterns you use in every component. For React hooks see react-hooks; for TypeScript type patterns see typescript-narrowing-patterns.

Interpolation and expressions

Curly braces {} switch from JSX to JavaScript. Any JS expression is valid inside them; statements are not.

PatternExampleNotes
Variable<p>{name}</p>Renders String(name)
Arithmetic<p>{count * 2}</p>Evaluated at render
Method call<p>{items.join(", ")}</p>Return value rendered
Template literal<p>{`Hello, ${name}`}</p>Nested template inside {}
Spread props<Input {...props} />Spread object as props
Prop expression<Button disabled={!isReady} />Boolean from expression
String prop<p className="foo" />Strings need no {}
Event handler<button onClick={() => doThing()}>Arrow function or reference
Ref callback<div ref={el => (ref.current = el)}>Imperative DOM access

0 renders as the string "0" in JSX. Guard with a boolean: {count > 0 && <Badge />} not {count && <Badge />}.

Conditional rendering

Four patterns; each has the right niche.

PatternSyntaxUse when
Ternary{cond ? <A /> : <B />}Two branches, neither is null
Short-circuit{cond && <A />}Show or show nothing; guard against 0
Nullish coalesce{value ?? <Fallback />}Show fallback only when value is null/undefined
Variableconst el = cond ? <A /> : null; return <>{el}</>Complex logic before the return
Early returnif (!data) return <Spinner />;Guard clauses; avoids deep nesting

Prefer early return over nested ternaries. A component that returns different roots based on loading/error/data states is easier to read with three early-return guards than one deeply nested ternary tree.

Fragments

Fragments let you return multiple sibling elements without adding a DOM node.

PatternSyntaxNotes
Short fragment<>...</>No props allowed
Long fragment<React.Fragment>...</React.Fragment>Accepts key prop
Fragment with key<React.Fragment key={id}>...</React.Fragment>Required when mapping
Avoid extra divreturn <><A /><B /></>;Common wrapper replacement

Use the long form only when you need the key prop. Otherwise prefer <>...</>.

Lists and the key prop

React uses key to reconcile list items across renders. Keys must be stable and unique among siblings.

PatternExampleNotes
Map with keyitems.map(i => <Li key={i.id} />)Use stable id, not index
Index as keyitems.map((i, idx) => <Li key={idx} />)Only when list never reorders
Fragment keyitems.map(i => <React.Fragment key={i.id}>…</React.Fragment>)Multiple nodes per item
Derived keykey={${cat}-${i.id}}Composite when ids collide across categories

Never use Math.random() or Date.now() as keys. They change on every render and destroy component state.

TypeScript-specific TSX patterns

TSX adds type annotations to props, events, and refs.

PatternSyntaxNotes
Typed propsfunction Card({ title }: { title: string })Inline type
Interface propsinterface Props { title: string } then function Card({ title }: Props)Preferred for reuse
Childrenchildren: React.ReactNodeMost permissive type for children
Event handleronChange: React.ChangeEvent<HTMLInputElement>Fully typed event
Click handleronClick: React.MouseEvent<HTMLButtonElement>Button-specific mouse event
Refref: React.RefObject<HTMLDivElement>From useRef<HTMLDivElement>(null)
Generic componentfunction List<T>({ items }: { items: T[] })Add trailing comma in TSX: <T,>
as const assertionconst v = ["a", "b"] as constNarrows to tuple literal

In .tsx files, <T> alone is ambiguous with JSX. Write <T,> or <T extends unknown> for generic arrow functions.

Common gotchas

  • {0 && <Component />} renders 0 to the DOM. Use {count > 0 && <Component />} or a ternary.
  • JSX attribute names are camelCase (className, htmlFor, tabIndex). HTML attributes in lowercase will work but produce a warning.
  • A component function must return JSX.Element, ReactNode, or null. Returning undefined throws in React 17 and below.
  • The key prop is not accessible inside the component via props.key. Pass the id separately if the component needs it.
  • Self-closing syntax (<Comp />) is required for JSX; HTML allows <Comp> without a close tag but JSX does not.
  • Fragments lose their key if you switch from <React.Fragment key={k}> to <>. The key is silently dropped.