Skip to main content

JSX

JSX Explained

Written by Published

JSX is syntax sugar for one function call. Once you have seen what it compiles to, most of its rules stop being arbitrary.

What it becomes

A JSX tag compiles to React.createElement(type, props, ...children). That is all. Your browser never sees JSX - a compiler rewrites it first, and on this site that happens as you press Run.

The same element, written twice

jsx

// JSX
const fromJsx = <h3 className="title">Hello</h3>

// Exactly what the compiler produces
const fromCall = React.createElement("h3", { className: "title" }, "Hello")

const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(
  <div>
    {fromJsx}
    {fromCall}
    <p>Both lines above produced identical output.</p>
  </div>
)

Because it is a function call, a JSX element is just a value. You can put it in a variable, return it from a function, or store it in an array - which is exactly what rendering a list does.

It is not HTML

The similarity is deliberate but shallow. A handful of attribute names differ, because the compiled output sets DOM properties rather than HTML attributes.

  • class becomes className - class is a reserved word in JavaScript.
  • for becomes htmlFor, for the same reason.
  • Attributes are camelCase: onclick is onClick, tabindex is tabIndex.
  • style takes an object, not a string: style={{ color: "red" }}.
  • Every tag must close.
    has to be
    .

The differences, side by side

jsx

function Styled() {
  return (
    <div>
      <p className="note" style={{ color: "#cc4600", fontWeight: 700 }}>
        className and a style object
      </p>
      <label htmlFor="email">htmlFor, not for</label>{" "}
      <input id="email" placeholder="you@example.com" />
      <br />
      <small>Self-closing tags are required.</small>
    </div>
  )
}

const root = ReactDOM.createRoot(document.getElementById("root"))
root.render(<Styled />)

Why the double braces

style={{ color: "red" }} looks strange until you separate the two pairs. The outer braces mean "a JavaScript expression follows". The inner braces are an ordinary object literal.

So it is one expression that happens to be an object - not special syntax. The same applies anywhere you see it.

Why JSX is optional but universal

You never have to use JSX. React.createElement is a normal function and some projects call it directly. In practice nearly everyone uses JSX, because nested createElement calls become unreadable at about three levels deep.

It matters that it is optional, though: JSX is not part of React and not part of JavaScript. It is a syntax extension that a compiler removes before the code ever runs, which is why a build step - or in this editor, Babel in the browser - is always involved.

  • JSX compiles to React.createElement; nothing more.
  • A JSX element is a value you can store, pass and return.
  • Attribute names follow the DOM property, not the HTML attribute.
  • It is a compiler feature, not something the browser understands.