Skip to Content
React in a Week
Day 1 · JS → first component

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.
Live code· JSX is a value

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 </>.

Live code· One root, with a Fragment

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:

HTMLJSX
classclassName
for (on a label)htmlFor
tabindextabIndex
onclickonClick

Two exceptions keep their dashes: aria-* and data-* attributes, such as aria-label and data-id, are written exactly as in HTML.

Live code· JSX attributes

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.

Live code· Curly braces

You can use curly braces in two places:

  1. As text inside a tag: <h2>{book.title}</h2>.
  2. 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.

Try it

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.)

Live code· Challenge: fix the JSX
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:

  1. Wrap the two top-level elements in a Fragment <>...</>.
  2. class becomes className (twice).
  3. <h2>title</h2> shows the word "title". Use {title} to show the variable.
  4. <img> and <input> must close themselves with />.
  5. for becomes htmlFor.
Quick check

Why do you have to write className instead of class in JSX?

Quick check

Which of these is valid JSX inside a component's return?

Day 1 progress

0/8
Next: Your first component

On this page