Skip to content

React Tutorial JSX and Components

JSX Under the Hood: How JSX Becomes JavaScript

Lesson 30 of 156 2 min read By Deepak Paswan Updated Oct 10, 2026

Runnable lesson · press Try it on the examples to edit and run them here.

Understanding what JSX turns into explains why its rules exist. You do not need this to write React, but it removes a lot of mystery.

JSX compiles to function calls

This JSX:

App.jsx
JSX
const element = <h1 className="title">Hello</h1>;

becomes, with the classic transform, this JavaScript:

script.js
JS
const element = React.createElement("h1", { className: "title" }, "Hello");

and with the automatic runtime that Vite and current React projects use:

script.js
JS
import { jsx as _jsx } from "react/jsx-runtime";

const element = _jsx("h1", { className: "title", children: "Hello" });

The automatic runtime is why you no longer need import React from "react" at the top of every file. (The playground uses the classic transform, which is why a global React exists there; the result is the same.)

What the function returns

Both calls return a plain object that describes the element. It is not a DOM node. You can look at it:

App.jsx
JSX
function App() {
  const element = <div className="card" id="c1"><span>Hi</span></div>;

  return (
    <pre>
      {`type: ${element.type}\nprops keys: ${Object.keys(element.props).join(", ")}\nclassName: ${element.props.className}\nchildren is a ${element.props.children.type}`}
    </pre>
  );
}

The element has a type ("div" for HTML tags, or the component function), a props object that includes children, and a few internal fields. This object is the Virtual DOM description you met in Understanding the Virtual DOM.

Why the JSX rules make sense now

RuleReason
Return one rootA function returns one value: one element object
className, htmlForAttributes become keys of a JavaScript object, and class/for are reserved words
Capital letter for componentscreateElement("div") makes an HTML tag; createElement(Greeting) calls a function. The compiler needs the capital to tell them apart
{} takes expressions onlyThe braces are arguments of a function call, and arguments must be expressions
style is an objectProps are JavaScript values, so style is an object
Close every tagJSX is a stricter language than HTML and must be parsed unambiguously

Components are called by React, not by you

<Greeting name="Ada" /> becomes createElement(Greeting, { name: "Ada" }). That object just records that a Greeting is wanted with those props. React calls the Greeting function later, during rendering. That is why you write <Greeting /> and never Greeting(): calling the function yourself would skip React and break features like state.

App.jsx
JSX
function Greeting({ name }) {
  return <p>Hi, {name}</p>;
}

function App() {
  const element = <Greeting name="Ada" />;
  // element is only a description: { type: Greeting, props: { name: "Ada" } }
  return (
    <div>
      {element}
      <small>element.type === Greeting: {String(element.type === Greeting)}</small>
    </div>
  );
}

Immutable descriptions

Elements are lightweight and read-only. You do not edit an element; you describe a new one in the next render. That is the same declarative idea from the first lessons.

Key points

  • JSX compiles to createElement or jsx calls that return plain description objects.
  • The JSX rules follow from how JavaScript functions and objects work.
  • React, not you, calls your components, so always use them as tags.