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.
| Pattern | Example | Notes |
|---|---|---|
| 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.
| Pattern | Syntax | Use 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 |
| Variable | const el = cond ? <A /> : null; return <>{el}</> | Complex logic before the return |
| Early return | if (!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.
| Pattern | Syntax | Notes |
|---|---|---|
| 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 div | return <><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.
| Pattern | Example | Notes |
|---|---|---|
| Map with key | items.map(i => <Li key={i.id} />) | Use stable id, not index |
| Index as key | items.map((i, idx) => <Li key={idx} />) | Only when list never reorders |
| Fragment key | items.map(i => <React.Fragment key={i.id}>…</React.Fragment>) | Multiple nodes per item |
| Derived key | key={${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.
| Pattern | Syntax | Notes |
|---|---|---|
| Typed props | function Card({ title }: { title: string }) | Inline type |
| Interface props | interface Props { title: string } then function Card({ title }: Props) | Preferred for reuse |
| Children | children: React.ReactNode | Most permissive type for children |
| Event handler | onChange: React.ChangeEvent<HTMLInputElement> | Fully typed event |
| Click handler | onClick: React.MouseEvent<HTMLButtonElement> | Button-specific mouse event |
| Ref | ref: React.RefObject<HTMLDivElement> | From useRef<HTMLDivElement>(null) |
| Generic component | function List<T>({ items }: { items: T[] }) | Add trailing comma in TSX: <T,> |
as const assertion | const v = ["a", "b"] as const | Narrows 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 />}renders0to 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, ornull. Returningundefinedthrows in React 17 and below. - The
keyprop is not accessible inside the component viaprops.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.