JSX - markup in JavaScript
The rules of JSX - one root element, closed tags, className and camelCase - and how curly braces open a window into JavaScript.
In the last lesson you saw components return something that looks like HTML. That is JSX: a syntax extension that lets you write markup inside JavaScript files.
Why mix them? On the web, rendering logic and markup are closely linked. A book card's markup depends on the book's data, and whether a badge appears depends on its status. React keeps the markup and the logic that drives it together, in one component, instead of spreading them over separate files.
JSX is JavaScript
JSX looks like HTML, but it is turned into ordinary JavaScript before it runs. Each tag becomes a function call that creates an object describing the element. That has two consequences you will feel straight away:
- JSX is stricter than HTML. Browsers forgive sloppy HTML; JavaScript tools do not.
- Some attribute names are different, because JSX attributes become JavaScript object keys.
Because JSX is a value, you can store it in a variable, return it from a function, or put it in an array. That is what makes map work for lists.
The rules of JSX
1. Return a single root element
A component can return only one top-level element. To return several, wrap them in a parent. If you do not want an extra <div> on the page, use a Fragment, written as empty tags <> and </>.
A Fragment groups elements without adding anything to the page. Under the hood, a component returns one value, and two side-by-side tags would be two values. The wrapper turns them into one.
2. Close every tag
In HTML you can leave some tags open, like <br> or <img>. In JSX every tag must be closed. Tags with no content close themselves with />.
// HTML style: not allowed in JSX
<img src="cover.jpg">
<br>
// JSX
<img src="cover.jpg" />
<br />3. camelCase most attributes
JSX attribute names become JavaScript keys, so they follow JavaScript naming. Names with dashes become camelCase (stroke-width becomes strokeWidth, onclick becomes onClick). Two names change completely, because class and for are reserved words in JavaScript:
| HTML | JSX |
|---|---|
class | className |
for (on a label) | htmlFor |
tabindex | tabIndex |
onclick | onClick |
Two exceptions keep their dashes: aria-* and data-* attributes, such as aria-label and data-id, are written exactly as in HTML.
The {' '} after the label adds a space. JSX removes line breaks between tags, so you add a space this way when you need one.
Curly braces: a window into JavaScript
Inside JSX, curly braces { } let you step back into JavaScript. Whatever expression you put inside is evaluated, and its result appears in the markup.
You can use curly braces in two places:
- As text inside a tag:
<h2>{book.title}</h2>. - As an attribute value, instead of quotes:
max={book.pages},value={120}. Use quotes for a fixed string (className="card") and curly braces for anything computed, including numbers.
Anything that produces a value works inside the braces: variables, maths, function calls, the ternary operator and template literals. Statements that do not produce a value, such as if or a for loop, do not work inside braces. You will see how to handle those on Day 2.
Deep diveDouble curlies: style={{ }}
The style attribute takes a JavaScript object, not a string. So you see two pairs of braces: the outer pair means "JavaScript here", and the inner pair is the object itself. CSS property names are camelCase there too:
<p style={{ color: 'teal', fontSize: 14 }}>Styled text</p>A plain number like 14 means 14px. Most of the time you will use className and a CSS file instead, which you will learn on Day 2.
Convert HTML to JSX
This markup was copied from an HTML page, so it breaks the JSX rules:
<h1 class="title">Book of the week</h1>
<article class="card">
<h2>title</h2>
<img src="emma.jpg" alt="Cover">
<label for="note">Your note</label>
<input id="note">
</article>Paste it into the sandbox in place of <p>Replace me</p> and fix it so it is valid JSX. The <h2> should show the value of the title variable. There are five problems. Until you have fixed all of the syntax ones, the sandbox shows an error, and that is expected. (The image will not load, because there is no emma.jpg file. Its alt text appears instead, which is fine.)
Show solution
const title = 'Emma';
export default function App() {
return (
<>
<h1 className="title">Book of the week</h1>
<article className="card">
<h2>{title}</h2>
<img src="emma.jpg" alt="Cover" />
<label htmlFor="note">Your note</label>
<input id="note" />
</article>
</>
);
}The five fixes:
- Wrap the two top-level elements in a Fragment
<>...</>. classbecomesclassName(twice).<h2>title</h2>shows the word "title". Use{title}to show the variable.<img>and<input>must close themselves with/>.forbecomeshtmlFor.
Why do you have to write className instead of class in JSX?
Which of these is valid JSX inside a component's return?
Day 1 progress