Use when writing JSX/TSX, rendering lists, implementing conditional rendering, or typing components with TypeScript generics. Prevents the common mistake of using unstable keys (like array index) or missing key props on list items. Covers JSX expressions, conditional rendering, list rendering with keys, fragments, TypeScript generics, spread attributes. Keywords: JSX, TSX, conditional rendering, key, Fragment, map, expressions, conditional render, show if true, loop over array, render list, key prop, Fragment..
Instrucciones de origen · Vista previa de solo lectura
name
react-syntax-jsx
description
Use when writing JSX/TSX, rendering lists, implementing conditional rendering, or typing components with TypeScript generics. Prevents the common mistake of using unstable keys (like array index) or missing key props on list items. Covers JSX expressions, conditional rendering, list rendering with keys, fragments, TypeScript generics, spread attributes. Keywords: JSX, TSX, conditional rendering, key, Fragment, map, expressions, conditional render, show if true, loop over array, render list, key prop, Fragment..
license
MIT
compatibility
Designed for Claude Code. Requires React 18.x or 19.x with TypeScript.
metadata
{"author":"OpenAEC-Foundation","version":"1.0"}
react-syntax-jsx
Quick Reference
JSX Compilation
JSX is syntactic sugar for React.createElement() calls. With the new JSX transform (React 17+, enabled by default in React 18/19), you do NOT need to import React for JSX to work:
// What you write:
<Button color="blue">Click me</Button>
{ jsx _jsx } ;
(, { : , : });
// What the compiler produces (new transform):
import
as
from
'react/jsx-runtime'
_jsx
Button
color
'blue'
children
'Click me'
NEVER import React solely for JSX in React 18/19 projects — the new JSX transform handles it automatically.
Three Rules of JSX
Return a single root element — use a wrapper <div> or Fragment <>...</>
Close ALL tags — including self-closing: <img />, <br />, <input />
camelCase for attributes — className, strokeWidth, onClick, htmlFor
Exceptions: aria-* and data-* attributes keep their dashes (e.g., aria-label, data-testid).
Attribute Name Mapping
HTML
JSX
Why
class
className
class is a reserved word in JavaScript
for
htmlFor
for is a reserved word in JavaScript
tabindex
tabIndex
camelCase convention
readonly
readOnly
camelCase convention
maxlength
maxLength
camelCase convention
aria-label
aria-label
Exception: kept as-is
data-id
data-id
Exception: kept as-is
Critical Warnings
NEVER use 0 && <Component /> — React renders the number 0 as visible text. ALWAYS convert the left side to a boolean:
// WRONG: Renders "0" on screen when count is 0
{messageCount && <Badge />}
// CORRECT: Boolean expression prevents rendering "0"
{messageCount > 0 && <Badge />}
NEVER use array index as key for lists that can reorder, insert, or delete items — this causes state corruption. ALWAYS use stable unique identifiers:
// WRONG: Index keys break on reorder/insert/delete
{items.map((item, index) =><Itemkey={index} {...item} />)}
// CORRECT: Stable unique ID preserves component state
{items.map((item) =><Itemkey={item.id} {...item} />)}
NEVER generate keys during render — Math.random() or crypto.randomUUID() inline creates new keys every render, destroying all component state.
NEVER use lowercase names for custom components — React treats lowercase tags as HTML elements. ALWAYS use PascalCase for component names.
Expressions in JSX
Use curly braces {} to embed JavaScript expressions inside JSX:
NEVER use statements inside {} — if, for, switch, let/const declarations are NOT expressions. Use ternaries, &&, or extract logic before the return.
String Literals vs Expressions
// String literal — use quotes
<input type="text" placeholder="Enter name" />
// Dynamic value — use braces<inputtype="text"placeholder={dynamicPlaceholder} />// NEVER mix quotes and braces on the same attribute<inputplaceholder="{'wrong'}" />// Renders the literal string "{'wrong'}"
Keys are NOT passed as a prop to the component — use a different prop name if needed
ALWAYS prefer database IDs or pre-generated stable IDs
Index as key is ONLY acceptable for static lists that never reorder
Fragments
Use Fragments to group elements without adding extra DOM nodes:
// Short syntax (cannot take props)
<>
<Header /><Main /><Footer />
</>
// Named Fragment (required when using key)import { Fragment } from'react';
{sections.map((section) => (
<Fragmentkey={section.id}><h2>{section.title}</h2><p>{section.content}</p></Fragment>
))}
ALWAYS use <Fragment key={...}> (named import) when you need keys on fragments — the short syntax <> does NOT support the key prop.
NEVER use React.FC<P> in new code — it previously included an implicit children prop (fixed in React 18 types) and hinders generic components. Direct annotation is clearer and more flexible.
Props spread FIRST can be overridden by explicit props that follow:
// className from defaults is overridden by the explicit className
<input {...defaults} className="custom" />
ALWAYS spread generic props first, then place specific overrides after — this ensures explicit props take precedence.
Boolean Attributes
// These are equivalent:
<input disabled />
<inputdisabled={true} />// To NOT disable:<inputdisabled={false} />// NEVER omit the value when you want false — omitting means true