The basics of JSX
In this chapter, you learn JSX, the syntax for describing React's UI.
What you'll learn in this chapter
- What JSX is and why you use it
- The four basic rules of JSX
- How to embed JavaScript
- How to apply inline styles
This chapter uses the project you created in Chapter 3. Start the development server with npm run dev and study while writing code.
Resetting the Vite template
The default Vite template includes demo styles. From here on you'll write your own code, so let's reset it to a simple state.
Replace src/index.css with the following content.
:root {
font-family: system-ui, -apple-system, sans-serif;
line-height: 1.5;
}
body {
margin: 0;
padding: 20px;
}
button {
padding: 8px 16px;
font-size: 1rem;
cursor: pointer;
}
nav a {
margin-right: 16px;
}
Replace src/App.css with the following content.
#root {
max-width: 800px;
margin: 0 auto;
text-align: center;
}
Now it's in a simple state. Text is centered, and the basic button style is in place.
In the code examples in the main text, the style import (import "./App.css") is sometimes omitted. The exercise answer code is written in complete form, so you can copy it directly into App.tsx and run it.
Your first JSX
Let's open src/App.tsx. The Vite template has a lot of code from the start, but we'll simplify it to learn the basics of JSX.
Rewrite src/App.tsx as follows.
function App() {
return <h1>Hello, React!</h1>
}
export default App
When you check the browser, "Hello, React!" is displayed. This <h1>Hello, React!</h1> is JSX.
What is JSX
JSX (JavaScript XML) is an extended syntax that lets you write HTML-like syntax inside JavaScript.
const element = <h1>Hello, React!</h1>
Browsers can't understand JSX directly, so it is converted to JavaScript at build time.
How JSX is converted internally
At build time, JSX is converted into calls to the jsx() function provided by react/jsx-runtime (the automatic runtime. It was introduced in React 17 and is the standard approach in Vite as well).
// Written in JSX
const element = <h1 className="title">Hello</h1>
// The converted JavaScript (conceptual; the import is inserted automatically at build time)
import { jsx as _jsx } from 'react/jsx-runtime'
const element = _jsx('h1', {
className: 'title',
children: 'Hello'
})
Note that in the traditional approach (the classic transform), it was converted to React.createElement('h1', { className: 'title' }, 'Hello'). You still see this form in explanatory articles, but in either approach the point that "one piece of JSX = one function call" is the same. Understanding this conversion explains the reasons for JSX's constraints (such as requiring a single root element).
The basic rules of JSX
1. A single root element
JSX must always return a single root element.
// OK: a single root element
const element = (
<div>
<h1>Title</h1>
<p>Body</p>
</div>
)
// NG: multiple root elements
const element = (
<h1>Title</h1>
<p>Body</p>
)
Fragment
When you don't want to add an extra DOM element, use a Fragment.
import { Fragment } from 'react'
const element = (
<Fragment>
<h1>Title</h1>
<p>Body</p>
</Fragment>
)
// Shorthand
const element = (
<>
<h1>Title</h1>
<p>Body</p>
</>
)
2. Closing tags are required
Closing tags that can be omitted in HTML are required in JSX.
// OK
<img src="image.png" alt="Image" />
<br />
<input type="text" />
// NG
<img src="image.png" alt="Image">
3. The className attribute
HTML's class attribute is written as className in JSX.
<div className="container">
<p className="text-primary">Text</p>
</div>
The reason you use className instead of class is that class is a reserved word in JavaScript. Since JSX runs inside JavaScript, you need to avoid collisions with reserved words.
4. camelCase
JSX attribute names are written in camelCase.
// HTML attribute → JSX attribute
// onclick → onClick
// tabindex → tabIndex
// for → htmlFor
<button onClick={handleClick}>Click</button>
<label htmlFor="email">Email</label>
Embedding JavaScript
Inside JSX, you can embed JavaScript expressions using curly braces {}. *Template literals and expressions are explained in Chapter 2.
Displaying a variable
const name = 'React'
const element = <h1>Hello, {name}!</h1>
Evaluating an expression
const element = <p>1 + 1 = {1 + 1}</p>
Calling a function
const formatDate = (date: Date) => date.toLocaleDateString()
const element = <p>Today: {formatDate(new Date())}</p>
An object's properties
const user = { name: 'Tanaka', age: 25 }
const element = <p>{user.name} (age {user.age})</p>
Applying styles
Inline styles
Inline styles are specified as an object.
const style = {
color: 'blue',
fontSize: '20px',
backgroundColor: '#f0f0f0'
}
const element = <p style={style}>Styled text</p>
// Writing it directly
const element = <p style={{ color: 'red', fontWeight: 'bold' }}>Text</p>
In inline styles, property names are camelCase (font-size → fontSize).
Comments
To write a comment inside JSX, wrap it in curly braces.
const element = (
<div>
{/* This is a comment */}
<p>Text</p>
</div>
)
Let's try it
Try the following exercises.
- Try className: Add
className="title"to<h1>and check how it's displayed - Try using class: Try using
classinstead ofclassNameand see what happens (check the warning) - Embed JavaScript: Define a variable
nameand display it with{name} - Try Fragment: Wrap multiple elements with
<>and</>
Hint
-
Just add
className="title". The attribute is applied even if no CSS is defined. Check the HTML element in your browser's developer tools. -
Open the browser console (F12 → Console), then save the code that uses the
classattribute. A warning message is displayed. Note that the editor shows a TypeScript type error (red underline), but the development server still runs. -
Define a variable inside the function, like
const name = 'React', and write{name}inside the JSX to display the variable's value. -
When you want to return multiple elements, wrap them with
<>and</>. For example, you can return<h1>and<p>side by side.
Answer and explanation
Exercise 1: Try className
import './App.css'
function App() {
return <h1 className="title">Hello, React!</h1>
}
export default App
When you add the className attribute, it's output as class="title" in HTML. If you open the Elements tab in your browser's developer tools (F12), you can confirm it becomes <h1 class="title">. If you define a style for the .title selector in CSS, the appearance changes.
Exercise 2: Try using class
import './App.css'
function App() {
return <h1 class="title">Hello, React!</h1>
}
export default App
A warning like the following is displayed in the browser console.
Invalid DOM property `class`. Did you mean `className`?
Because class is a reserved word in JavaScript (used for class definitions), you need to use className in JSX. Since React 16, an incorrect attribute name is also stringified with a warning and passed to the DOM as-is, so class="title" itself is rendered, but during development the above warning appears in the console. React's official recommendation is always className, so use className in new code. Also, in TypeScript projects the class attribute is detected as a type error (Did you mean 'className'?) in the editor as well. Being able to notice the mistake before running is one of the advantages of using TypeScript. Once you've checked it, switch back to className.
Exercise 3: Embed JavaScript
import './App.css'
function App() {
const name = 'React'
return <h1>Hello, {name}!</h1>
}
export default App
When you write a JavaScript expression inside curly braces {}, its evaluation result is displayed. Not only variables but also calculations like {1 + 1} and method calls like {name.toUpperCase()} are possible.
Exercise 4: Try Fragment
import './App.css'
function App() {
return (
<>
<h1>Title</h1>
<p>This is the body</p>
</>
)
}
export default App
Using <> and </> (a Fragment), you can return multiple elements without adding an extra <div>. It's useful when you want to keep the HTML structure simple. If you check the developer tools, you can see that <h1> and <p> are placed directly inside <div id="root">.
Summary
- JSX lets you write HTML-like syntax inside JavaScript
- A single root element is required (you can work around this with a Fragment)
- Closing tags are required
classbecomesclassName, and attributes are camelCase- You can embed JavaScript expressions with
{}
Until you get used to JSX, you may get errors from its differences with HTML. In particular, keep in mind the use of className, the requirement for closing tags, and camelCase attribute names.
In the next chapter, you learn about components, the core of React.