← React & TypeScript

React Fundamentals

What is JSX and how does it differ from HTML?

Show answer — try answering out loud first

JSX is a JavaScript syntax extension that lets you write HTML-like markup inside your code. It's not HTML: it's syntactic sugar that the compiler transforms into calls to React functions (like createElement or the JSX runtime), that is, into JavaScript objects.

When you write <h1>Hola</h1> in a component, the browser never sees that. A build tool (Babel, SWC, the TypeScript compiler...) transforms it into a function call that returns an object describing that element. React uses those objects to know what to render.

Key points worth being clear on:

  • It's JavaScript, not HTML: that's why you can store it in variables, return it from functions, or pass it as an argument.
  • Expressions with curly braces {}: inside the braces you can put any JavaScript expression (variables, ternaries, function calls). You can't put statements like if or for directly.
  • Attributes with JavaScript names: since class and for are reserved words, JSX uses className and htmlFor. Attributes are written in camelCase (onClick, tabIndex).
  • A single root element: a JSX expression must return a single node. If you need several siblings without wrapping them in a <div>, you use a Fragment (<>...</>).
// What you write...
const saludo = <h1 className="titulo">Hola, Mike</h1>;

// ...compiles to something equivalent to this (classic runtime):
// const saludo = React.createElement("h1", { className: "titulo" }, "Hola, Mike");
// That is: JSX produces JavaScript objects, not HTML.

type Props = { nombre: string; esAdmin: boolean };

function TarjetaUsuario({ nombre, esAdmin }: Props) {
  // Fragment (<>...</>) to return several siblings without an extra div
  return (
    <>
      {/* The braces evaluate JavaScript expressions */}
      <h2>{nombre.toUpperCase()}</h2>
      <p>Rol: {esAdmin ? "Administradora" : "Usuaria"}</p>
      {/* htmlFor instead of for, className instead of class */}
      <label htmlFor="correo" className="etiqueta">Correo</label>
      <input id="correo" type="email" />
    </>
  );
}

// <TarjetaUsuario nombre="Ana" esAdmin={true} /> renders:
// ANA / Rol: Administradora / and the email field with its label.

Trying to return several root elements or using HTML attributes as-is:

// BAD: two root elements and the `class` attribute
function Perfil() {
  return (
    <h1 class="titulo">Perfil</h1>
    <p>Bienvenida</p>
  ); // Compilation error: JSX must have a single root element
}

// GOOD: Fragment as the root and className instead of class
function PerfilCorregido() {
  return (
    <>
      <h1 className="titulo">Perfil</h1>
      <p>Bienvenida</p>
    </>
  );
}

"JSX is a syntax extension that lets me describe the UI with something similar to HTML, but inside JavaScript. It's really syntactic sugar: the compiler turns it into calls to React functions that return objects. That's why there are differences from HTML, like using className instead of class or htmlFor instead of for. Inside braces I can evaluate any JavaScript expression, and each JSX block must have a single root element; if I need several siblings, I use a Fragment to avoid adding unnecessary divs."

Quick challenge

Fix this component so it compiles and works (it has three JSX-related errors):

function Formulario() {
  const titulo = "Registro";
  return (
    <label for="nombre">titulo</label>
    <input id="nombre" class="campo" />
  );
}
See solution
function Formulario() {
  const titulo = "Registro";
  return (
    // 1. Fragment: JSX needs a single root element.
    // 2. htmlFor and braces to evaluate the variable. 3. className.
    <>
      <label htmlFor="nombre">{titulo}</label>
      <input id="nombre" className="campo" />
    </>
  );
}