React 5 ⚛️ JSX Syntax and Rules
JSX is the syntax that lets you write markup inside JavaScript. It looks like HTML, but it is not HTML. It is a syntax extension that the compiler transforms into JavaScript function calls. Every React component returns JSX. Every React application is built from JSX. Understanding the rules of JSX is the first step to writing React that compiles and runs.
The previous chapter covered the project structure. This chapter covers the language you write inside that structure. JSX is not a template language. It is a JavaScript expression. That distinction explains every rule: why tags must be closed, why attributes use camelCase, why curly braces open a window to JavaScript, and why a component can return only one root element.
Key point: JSX is not HTML. It is a syntax extension that looks like HTML but compiles to React.createElement() calls. The result is a plain JavaScript object called a React element. React reads these objects to build the virtual DOM. Every rule of JSX exists because JSX must be valid JavaScript once the compiler transforms it.
Why JSX Exists
Before JSX, React components were written with React.createElement() calls. The code was verbose and unreadable. A simple greeting required nested function calls. JSX was introduced to make the structure visible.
The readability problem. A component that renders a list with headings and paragraphs is a tree of elements. Writing the tree as nested function calls obscures the structure. Writing it as JSX makes the structure visible. The markup looks like the output.
The expression problem. JSX is an expression, not a statement. It can be assigned to a variable, passed as an argument, returned from a function. This is what makes components composable: a component returns JSX, and that JSX can be used anywhere an expression can be used.
The compiler problem. JSX is not valid JavaScript. It requires a compiler to transform it. Babel and SWC both handle JSX. The compiler transforms <h1>Hello</h1> into React.createElement('h1', null, 'Hello'). The result is a plain object that React can render.
The trade-off. JSX requires a build step. The compiler must be configured. The syntax is not standard JavaScript. But the readability and the composability are worth the cost. Every React project uses JSX.
a. The JSX Expression
A JSX expression is a piece of markup that evaluates to a React element. It can appear anywhere a JavaScript expression can appear.
const element = <h1>Hello, world!</h1>;
The expression <h1>Hello, world!</h1> is not a string. It is a React element — a plain object that describes the <h1> tag and its content. React reads the object and creates the corresponding DOM element.
JSX can be embedded in a return statement:
function Greeting() {
return <h1>Hello, world!</h1>;
}
The function returns the React element. React calls the function, receives the element, and renders it.
JSX can contain JavaScript expressions inside curly braces:
const name = 'Alice';
const element = <h1>Hello, {name}!</h1>;
The curly braces open a window to JavaScript. The expression name is evaluated, and its value is inserted into the output. The result is <h1>Hello, Alice!</h1>.
The curly braces can contain any JavaScript expression: variables, function calls, arithmetic, ternary operators, template literals.
const user = { name: 'Alice', age: 30 };
const element = <p>{user.name} is {user.age} years old.</p>;
const sum = <p>{1 + 2 + 3}</p>;
const status = <p>{isActive ? 'Active' : 'Inactive'}</p>;
const message = <p>{`Hello, ${user.name}!`}</p>;
Each expression is evaluated and its result is inserted. The curly braces are the bridge between the static markup and the dynamic data.
b. The Rules of JSX
JSX has specific rules. Each rule exists because JSX must compile to valid JavaScript.
Return a single root element. A component must return one element, not multiple. The element can contain any number of children, but the top level must be a single element.
// ❌ Invalid: two root elements
function App() {
return (
<h1>Title</h1>
<p>Body</p>
);
}
// ✅ Valid: one root element
function App() {
return (
<div>
<h1>Title</h1>
<p>Body</p>
</div>
);
}
// ✅ Valid: a fragment
function App() {
return (
<>
<h1>Title</h1>
<p>Body</p>
</>
);
}
The fragment <>...</> is a special syntax that groups elements without adding a wrapper to the DOM. It is the idiomatic way to return multiple elements from a component.
Close every tag. Unlike HTML, JSX requires every tag to be closed. Self-closing tags use />.
// ✅ Valid
<img src="avatar.jpg" alt="Avatar" />
<br />
<input type="text" />
// ❌ Invalid
<img src="avatar.jpg" alt="Avatar">
<br>
<input type="text">
Use camelCase for attributes. HTML attributes like class, for, and onclick are reserved words in JavaScript. JSX uses camelCase: className, htmlFor, onClick.
// ✅ Valid
<div className="container">
<label htmlFor="name">Name</label>
<button onClick={handleClick}>Click</button>
// ❌ Invalid
<div class="container">
<label for="name">Name</label>
<button onclick={handleClick}>Click</button>
Use curly braces for expressions, not quotes. A string literal in JSX is treated as text. A JavaScript expression must be inside curly braces.
// ✅ Valid: expression
<img src={avatarUrl} alt={user.name} />
// ❌ Invalid: quotes around an expression
<img src="{avatarUrl}" alt="{user.name}" />
Style is an object, not a string. The style attribute accepts a JavaScript object with camelCase property names.
// ✅ Valid
<div style={{ color: 'red', fontSize: '16px' }}>
Styled text
</div>
// ❌ Invalid
<div style="color: red; font-size: 16px;">
Styled text
</div>
The double curly braces are not a special syntax. The outer pair opens a JavaScript expression. The inner pair is the object literal.
Keys in lists. When rendering a list with .map(), each element needs a key prop. The key must be unique among siblings. It is how React tracks items between renders.
function List({ items }) {
return (
<ul>
{items.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
The key is not passed to the component as a prop. It is used by React internally for reconciliation. If a component needs the value, it must receive it under a different prop name.
c. JSX and Conditional Rendering
Conditional rendering in JSX uses JavaScript expressions. There is no if statement inside JSX. The logic happens in the surrounding JavaScript.
Ternary operator. The most common pattern for two branches.
function Status({ isActive }) {
return (
<span className={isActive ? 'active' : 'inactive'}>
{isActive ? 'Active' : 'Inactive'}
</span>
);
}
The ternary is an expression, so it can be embedded directly in JSX.
Logical AND. The && operator is the shorthand for “render this if the condition is true.”
function Notification({ message }) {
return (
<div>
{message && <p className="notification">{message}</p>}
</div>
);
}
If message is truthy, the <p> renders. If it is falsy, nothing renders.
There is a common trap with &&. If the left side is 0, the expression evaluates to 0, and React renders the number 0 on the screen. Use a ternary or a comparison when the value could be 0.
// ❌ Renders "0" when count is 0
{count && <p>Count: {count}</p>}
// ✅ Renders nothing when count is 0
{count > 0 && <p>Count: {count}</p>}
Returning null. A component can return null to render nothing.
function Warning({ show, message }) {
if (!show) {
return null;
}
return <div className="warning">{message}</div>;
}
The early return keeps the JSX clean. The component renders nothing when the condition is false.
Variables for branches. A variable can hold the JSX for a branch.
function Greeting({ isLoggedIn }) {
let content;
if (isLoggedIn) {
content = <h1>Welcome back!</h1>;
} else {
content = <h1>Please sign up.</h1>;
}
return <div>{content}</div>;
}
The if/else statement computes the content, and the JSX renders the variable. This pattern is useful when the branches are complex.
| Pattern | Use Case |
|---|---|
condition ? a : b | Two branches |
condition && a | One branch, truthy check |
if (!condition) return null | Early return |
let content; if... | Complex branches |
Complete Example Session
This session demonstrates the JSX rules with a small component.
// ============================================
// PART 1: THE BASIC JSX EXPRESSION
// ============================================
const element = <h1>Hello, world!</h1>;
// A React element.
// ============================================
// PART 2: THE COMPONENT
// ============================================
function Welcome() {
return <h1>Hello, world!</h1>;
}
// The component returns a React element.
// ============================================
// PART 3: EXPRESSIONS IN JSX
// ============================================
const name = 'Alice';
const age = 30;
function Greeting() {
return (
<div>
<h1>Hello, {name}!</h1>
<p>You are {age} years old.</p>
<p>Next year you will be {age + 1}.</p>
<p>Status: {age >= 18 ? 'Adult' : 'Minor'}</p>
</div>
);
}
// The curly braces evaluate JavaScript expressions.
// ============================================
// PART 4: THE SINGLE ROOT ELEMENT
// ============================================
// ❌ Invalid: two root elements
// function Broken() {
// return (
// <h1>Title</h1>
// <p>Body</p>
// );
// }
// ✅ Valid: one root element
function Fixed() {
return (
<div>
<h1>Title</h1>
<p>Body</p>
</div>
);
}
// ✅ Valid: a fragment
function FragmentExample() {
return (
<>
<h1>Title</h1>
<p>Body</p>
</>
);
}
// ============================================
// PART 5: CLOSING TAGS
// ============================================
function Images() {
return (
<div>
<img src="avatar.jpg" alt="Avatar" />
<br />
<input type="text" />
</div>
);
}
// Every tag is closed.
// Self-closing tags use />.
// ============================================
// PART 6: CAMELCASE ATTRIBUTES
// ============================================
function Form() {
return (
<form>
<label htmlFor="name">Name</label>
<input id="name" type="text" className="input" />
<button onClick={() => alert('Clicked')}>Submit</button>
</form>
);
}
// className, htmlFor, onClick are camelCase.
// ============================================
// PART 7: THE STYLE ATTRIBUTE
// ============================================
function StyledBox() {
const style = {
color: 'red',
fontSize: '16px',
backgroundColor: 'lightyellow',
};
return <div style={style}>Styled text</div>;
}
// The style prop accepts an object.
// The property names are camelCase.
// ============================================
// PART 8: CONDITIONAL RENDERING
// ============================================
function UserStatus({ isLoggedIn, username }) {
return (
<div>
{isLoggedIn ? (
<h1>Welcome back, {username}!</h1>
) : (
<h1>Please sign in.</h1>
)}
</div>
);
}
function Notification({ count }) {
return (
<div>
{count > 0 && <p>You have {count} new messages.</p>}
</div>
);
}
// The ternary renders two branches.
// The && renders one branch when the condition is true.
// ============================================
// PART 9: LIST RENDERING WITH KEYS
// ============================================
function TodoList({ todos }) {
return (
<ul>
{todos.map(todo => (
<li key={todo.id}>
{todo.text}
</li>
))}
</ul>
);
}
const todos = [
{ id: 1, text: 'Learn JSX' },
{ id: 2, text: 'Build a component' },
{ id: 3, text: 'Render a list' },
];
// Each item has a key.
// The key is unique among siblings.
// ============================================
// PART 10: THE SUMMARY
// ============================================
// JSX is a syntax extension.
// It compiles to React.createElement() calls.
// Return a single root element.
// Close every tag.
// Use camelCase for attributes.
// Use curly braces for expressions.
// Style is an object.
// Keys are required in lists.
The ten parts cover the basic JSX expression, the component, expressions in JSX, the single root element, closing tags, camelCase attributes, the style attribute, conditional rendering, list rendering with keys, and the summary.
Quick Reference
The JSX Rules
| Rule | Reason |
|---|---|
| Single root element | JSX must return one expression |
| Close every tag | JSX is not HTML |
| camelCase attributes | HTML attributes conflict with JS |
| Curly braces for expressions | JSX treats quotes as strings |
style is an object | style is a JS object, not a string |
| Keys in lists | React tracks items by key |
The Attribute Names
| HTML | JSX |
|---|---|
class | className |
for | htmlFor |
onclick | onClick |
tabindex | tabIndex |
maxlength | maxLength |
style="..." | style={{...}} |
The Conditional Patterns
| Pattern | Use Case |
|---|---|
{cond ? a : b} | Two branches |
{cond && a} | One branch, truthy |
if (!cond) return null | Early return |
let content; if... | Complex branches |
The Fragment
| Syntax | Purpose |
|---|---|
<>...</> | Group elements without a wrapper |
<React.Fragment>...</React.Fragment> | Explicit fragment with key support |
Best Practices
✅ Do This:
// Return a single root element
return <div><h1>Title</h1></div>; // ✅
// Use fragments to avoid extra wrappers
return <><h1>Title</h1><p>Body</p></>; // ✅
// Use camelCase attributes
<button onClick={handleClick}>Click</button> // ✅
// Use an object for style
<div style={{ color: 'red' }}>Text</div> // ✅
// Use a key in list rendering
{items.map(item => <li key={item.id}>{item.name}</li>)} // ✅
❌ Don’t Do This:
// Don't return multiple root elements
return <h1>Title</h1><p>Body</p>; // ❌
// Don't use HTML attribute names
<div class="container"> // ❌
// Don't use quotes for expressions
<img src="{avatarUrl}" /> // ❌
// Don't use a string for style
<div style="color: red;">Text</div> // ❌
// Don't forget keys in lists
{items.map(item => <li>{item.name}</li>)} // ❌
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| Syntax error | Multiple root elements | Use a fragment |
| Attribute not applied | Wrong name | Use camelCase |
| Expression renders as text | Quotes used | Use curly braces |
| Style not applied | String used | Use an object |
| List re-renders | Missing key | Add a unique key |
0 renders | && with zero | Use count > 0 && |
Real-World Examples
1. Basic Element
const element = <h1>Hello</h1>;
2. Component
function Hello() {
return <h1>Hello</h1>;
}
3. Expression
<p>{user.name}</p>
4. Arithmetic
<p>{price * quantity}</p>
5. Ternary
{isActive ? 'Active' : 'Inactive'}
6. Logical AND
{hasError && <p className="error">{error}</p>}
7. Style Object
<div style={{ color: 'red', fontSize: '16px' }} />
8. Fragment
<>
<h1>Title</h1>
<p>Body</p>
</>
9. List with Keys
{items.map(item => <li key={item.id}>{item.name}</li>)}
10. Early Return
if (!show) return null;
return <div>{content}</div>;
Visual
The JSX Transformation
┌──────────────────────────────────────────────┐
│ JSX │
│ <h1 className="title">Hello</h1> │
│ │
│ COMPILES TO │
│ │
│ React.createElement( │
│ 'h1', │
│ { className: 'title' }, │
│ 'Hello' │
│ ) │
│ │
│ The result is a plain object. │
│ │
└──────────────────────────────────────────────┘
The Single Root Rule
┌──────────────────────────────────────────────┐
│ ❌ INVALID │
│ return ( │
│ <h1>Title</h1> │
│ <p>Body</p> │
│ ); │
│ │
│ ✅ VALID │
│ return ( │
│ <> │
│ <h1>Title</h1> │
│ <p>Body</p> │
│ </> │
│ ); │
│ │
└──────────────────────────────────────────────┘
The Curly Braces
┌──────────────────────────────────────────────┐
│ QUOTES: string │
│ <img src="avatar.jpg" /> │
│ │
│ CURLY BRACES: JavaScript expression │
│ <img src={avatarUrl} /> │
│ │
│ The two are different. │
│ Use quotes for literal strings. │
│ Use curly braces for expressions. │
│ │
└──────────────────────────────────────────────┘
The Key Prop
┌──────────────────────────────────────────────┐
│ WITHOUT KEY: │
│ {items.map(item => <li>{item.name}</li>)}│
│ React warns. │
│ Items may re-render incorrectly. │
│ │
│ WITH KEY: │
│ {items.map(item => ( │
│ <li key={item.id}>{item.name}</li> │
│ ))} │
│ React tracks items. │
│ Efficient updates. │
│ │
└──────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| JSX definition | Syntax extension that looks like HTML |
| Compiles to | React.createElement() |
| Result | A React element |
| Root element | One per component |
| Fragment | <>...</> |
| Attributes | camelCase |
| Expressions | Curly braces |
| Style | Object with camelCase properties |
| Keys | Required in lists |
| Conditional | Ternary, &&, early return |
| Component name | Capitalized |
Key takeaways:
- JSX is a syntax extension, not HTML. It compiles to
React.createElement()calls that produce plain JavaScript objects called React elements. React reads these objects to build the virtual DOM . - A component must return a single root element. The root can be a JSX element or a fragment. The fragment
<>...</>groups elements without adding a wrapper to the DOM . - Every tag must be closed. Unlike HTML, JSX requires all tags to be closed. Self-closing tags use
/>. This is because JSX is transformed into JavaScript, and the transformation requires well-formed syntax . - Attributes use camelCase. The HTML attributes
class,for, andonclickare reserved words in JavaScript. JSX usesclassName,htmlFor, andonClick. Thestyleattribute accepts a JavaScript object with camelCase properties . - Curly braces open a window to JavaScript. Any expression can be embedded: variables, arithmetic, function calls, ternaries. The expression is evaluated, and its result is inserted into the output .
- Conditional rendering uses JavaScript expressions. There is no
ifstatement inside JSX. Use the ternary operator for two branches, the&&operator for one branch, or an early return for complex logic . - Keys are required in list rendering. The
keyprop gives each item a stable identity. React uses the key to track items between renders. The key must be unique among siblings and should not be the array index if the list can change .
Remember: JSX is the language of React components. It is not HTML. It compiles to JavaScript. It follows specific rules: single root, closed tags, camelCase attributes, curly braces for expressions, an object for style, and keys in lists. The rules are not arbitrary. They exist because JSX must be valid JavaScript. Once you internalize the rules, writing JSX is as natural as writing HTML.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!