Getting started with JSX
By Flavio Copes
Learn the JSX syntax React uses for UI: elements, props, JavaScript expressions, styles, forms, fragments, escaping, and rendering lists with keys.
- What is JSX?
- The main JSX rules
- Use JavaScript expressions in JSX
- Pass props
- Add styles
- Use forms
- JSX escapes values
- Add comments
- Spread props
- Render a list
What is JSX?
JSX is a JavaScript syntax extension that lets you write HTML-like markup inside a JavaScript file.
React does not require JSX, but most React projects use it. It keeps a component’s rendering logic and markup together.
Here’s a JSX element:
const element = <h1>Hello, world!</h1>
JSX is not HTML inside a string. A build tool transforms it into JavaScript calls that create React elements.
Modern React frameworks and build tools usually configure this step for you. Babel, SWC, and other compilers can perform the transform.
The official React JSX guide covers the syntax rules.
The main JSX rules
JSX looks like HTML, but it is stricter.
Return one root element
A component must return one root JSX element:
function Page() {
return (
<main>
<h1>My blog</h1>
<p>Latest posts</p>
</main>
)
}
If you do not want an extra DOM element, use a Fragment:
function Page() {
return (
<>
<h1>My blog</h1>
<p>Latest posts</p>
</>
)
}
The short <>...</> syntax groups elements without adding a wrapper to the rendered HTML.
Close every tag
JSX requires every tag to be closed:
<>
<img src="/avatar.png" alt="Flavio" />
<br />
</>
Tags with children need both an opening and closing tag:
<p>Hello</p>
Use React DOM prop names
Most HTML and SVG attributes use camelCase in JSX:
<button onClick={handleClick}>Save</button>
Two common differences are:
classbecomesclassNameforbecomeshtmlFor
Example:
<label htmlFor="email" className="field-label">
Email
</label>
data-* and aria-* attributes keep their dashes:
<button data-action="save" aria-label="Save post">
Save
</button>
See the React DOM common props reference for the complete list.
Use JavaScript expressions in JSX
Put a JavaScript expression inside curly braces:
const name = 'Flavio'
const heading = <h1>Hello, {name}</h1>
You can use variables, property access, function calls, and other expressions:
const user = {
name: 'Flavio',
posts: 12
}
const profile = (
<p>
{user.name} wrote {user.posts} posts
</p>
)
Curly braces accept expressions, not statements. You cannot put an if statement or a for loop directly inside JSX.
For conditional output, calculate the value first or use a conditional expression:
const message = isLoggedIn
? <p>Welcome back</p>
: <p>Please sign in</p>
Pass props
Text props can use quotes:
<img src="/avatar.png" alt="Flavio" />
Use curly braces for numbers, objects, functions, and variables:
<Avatar
size={80}
user={user}
onSelect={handleSelect}
/>
Custom component names start with an uppercase letter. Lowercase JSX names represent built-in HTML elements.
Add styles
Use className for regular CSS classes:
<p className="description">A short introduction</p>
The style prop accepts an object. CSS property names use camelCase:
const color = 'tomato'
const message = (
<p style={{ color, marginTop: 20 }}>
A highlighted message
</p>
)
Style values can be strings or numbers. React adds px to numeric values when the CSS property requires a length.
Use style when a value depends on JavaScript data. For regular styling, React recommends CSS classes.
Use forms
React supports controlled and uncontrolled form fields.
Use defaultValue to set an uncontrolled field’s initial value:
<input name="name" defaultValue="Flavio" />
Use value and onChange when React state controls the current value:
import { useState } from 'react'
function NameField() {
const [name, setName] = useState('')
return (
<input
value={name}
onChange={event => setName(event.target.value)}
/>
)
}
A controlled input must update its value in onChange. Otherwise it becomes read-only.
Checkboxes and radio buttons use checked and defaultChecked.
The input React reference explains controlled and uncontrolled fields in detail.
JSX escapes values
React escapes strings rendered through JSX expressions:
const comment = '<img src=x onerror=alert(1)>'
const message = <p>{comment}</p>
The text appears as text. React does not interpret it as an HTML element.
This prevents many cross-site scripting problems. Be very careful with dangerouslySetInnerHTML: only use HTML from a trusted or properly sanitized source.
HTML entities work when you write them directly in JSX:
<p>© 2026</p>
You can also use the Unicode character:
<p>{'\u00A9 2026'}</p>
Add comments
Put a JavaScript block comment inside curly braces:
<section>
{/* Show the latest posts */}
<PostList />
</section>
Spread props
You can spread an object’s properties into a component:
const post = {
title: 'Learning React',
date: '2026-07-18'
}
const card = <BlogPost {...post} />
Property order matters. A later prop with the same name overwrites an earlier one:
<BlogPost {...post} title="A different title" />
Use spread props when the object and component share a clear contract. Explicit props are easier to read when you only pass a few values.
Render a list
Use map() to turn data into JSX elements:
const posts = [
{ id: 1, title: 'Learning React' },
{ id: 2, title: 'Learning JavaScript' }
]
function PostList() {
return (
<ul>
{posts.map(post => (
<li key={post.id}>{post.title}</li>
))}
</ul>
)
}
Each element created inside map() needs a stable key among its siblings.
Use an ID from your data when possible. Array indexes can cause incorrect state matching when items move, are inserted, or are removed.
Read the official React list rendering guide for more examples.
Related posts about react: