JSX es una extensión de sintaxis de JavaScript que te permite escribir marcado parecido a HTML dentro de tu código. Los componentes de React devuelven JSX para describir lo que debe aparecer en pantalla, y una herramienta de build lo compila a llamadas de función de JavaScript normales. Se parece a HTML, pero algunas reglas cambian, y las llaves te permiten poner cualquier valor de JavaScript en el marcado.
Todo lo que está dentro de {} es JavaScript: una propiedad, una llamada a un método, incluso map convirtiendo un array en elementos de lista. Agrega 'design' al array skills y se actualizan tanto el conteo como la lista.
Reglas de JSX
Devuelve un solo elemento raíz
Un componente devuelve un único valor, así que su JSX necesita un único padre. Dos hermanos en el nivel superior son un error de sintaxis. Cuando no quieras un <div> extra en la página, envuélvelos en un fragmento, <>...</>:
// Error: Adjacent JSX elements must be wrapped in an enclosing tag
return (
<h1>Title</h1>
<p>Text</p>
);
// OK: a fragment groups them without adding a DOM element
return (
<>
<h1>Title</h1>
<p>Text</p>
</>
);
Cuando necesites una key en el grupo, usa la forma larga <Fragment key={id}>; consulta fragmentos.
Cierra todas las etiquetas
HTML te deja algunas etiquetas abiertas. JSX no. Los elementos sin hijos se cierran solos con />: <img />, <br />, <input /> y tus propios componentes como <Avatar />.
Usa className, htmlFor y atributos en camelCase
Los atributos de JSX se convierten en claves de un objeto de JavaScript, así que siguen la nomenclatura de JavaScript. class y for son palabras reservadas en JavaScript, y por eso JSX usa className y htmlFor. Los atributos de varias palabras y todos los manejadores de eventos van en camelCase: tabIndex, maxLength, autoFocus, onClick, onChange. Dos excepciones conservan sus guiones: los atributos aria-* y data-* se escriben exactamente como en HTML.
Cambia className="field" por class="field". La etiqueta conserva su estilo, porque React igual asigna el atributo, pero un build de desarrollo registra "Invalid DOM property class. Did you mean className?" La vista previa funciona como un build de producción, así que aquí no verás esa advertencia; usa className. Un atributo de tipo cadena usa comillas (type="email"); cualquier otro valor usa llaves (maxLength={40}, disabled={false}).
Las llaves aceptan expresiones, no sentencias
Dentro de {} puedes escribir cualquier cosa que produzca un valor: una variable, aritmética, una llamada a función, un ternario, &&, un template literal. Sentencias como if, for y const no producen un valor, así que no pueden ir ahí. Haz el trabajo antes del return, o usa una forma de expresión:
Mira con atención antes de hacer clic: la página muestra un 0 suelto. count && <p>...</p> se evalúa como 0 cuando el contador es cero, y React renderiza números, incluso el cero. Cámbialo por count > 0 && <p>You have mail.</p> y el 0 desaparece. false, null, undefined y true no renderizan nada, y por eso un booleano a la izquierda de && es seguro. La página sobre renderizado condicional cubre los patrones.
Los estilos en línea usan un objeto
El atributo style recibe un objeto de JavaScript, no una cadena CSS. De ahí el aspecto de "llaves dobles": el par exterior significa "aquí va JavaScript", el interior es el literal de objeto. Los nombres de las propiedades van en camelCase (backgroundColor, fontSize), y un número sin unidad significa píxeles para la mayoría de las propiedades de tamaño.
Como el estilo es un objeto, se puede calcular a partir del estado como cualquier otro valor. Prueba a cambiar fontSize: big ? 24 : 16 por fontSize: big ? '2em' : '1em': las cadenas se pasan tal cual con su unidad.
Comentarios
Un comentario dentro de JSX va entre llaves: {/* this is a comment */}. Los comentarios HTML (<!-- -->) son un error de sintaxis. Fuera del marcado, en el cuerpo de la función, los comentarios // normales funcionan como siempre.
return (
<div>
{/* The header is hidden on small screens */}
<Header />
</div>
);
Convertir HTML a JSX
Pegar HTML en un componente es un primer paso habitual, y casi todo funciona. Estos son los cambios que normalmente tienes que hacer:
classpasa a serclassName, yforpasa a serhtmlFor.- Las etiquetas vacías se cierran solas:
<br>pasa a ser<br />,<img src="a.png">pasa a ser<img src="a.png" />. style="color: red; font-size: 14px"pasa a serstyle={{ color: 'red', fontSize: 14 }}.- Los atributos de eventos reciben una función, no una cadena:
onclick="save()"pasa a seronClick={save}. - Los nombres de atributos pasan a camelCase:
tabindexpasa a sertabIndex, y elstroke-widthde SVG pasa a serstrokeWidth. <!-- comments -->pasa a ser{/* comments */}.- Varios elementos de nivel superior necesitan un padre o un fragmento.
Los conversores de HTML a JSX en línea hacen estos pasos por ti, pero conocerlos hace que los mensajes de error sean fáciles de leer cuando se te pasa uno.
En qué se compila JSX
Los navegadores no pueden ejecutar JSX. Un compilador (como Babel, SWC u Oxc, que Vite y los frameworks ejecutan por ti) convierte cada etiqueta en una llamada a función de react/jsx-runtime:
// What you write
const element = <h1 className="title">Hello, {name}</h1>;
const button = <Button size="small">OK</Button>;
// What the compiler produces (roughly)
import { jsx as _jsx, jsxs as _jsxs } from 'react/jsx-runtime';
const element = _jsxs('h1', { className: 'title', children: ['Hello, ', name] });
const button = _jsx(Button, { size: 'small', children: 'OK' });
Una etiqueta en minúscula se convierte en una cadena ('h1', un elemento HTML), una con mayúscula se convierte en una referencia a tu función (Button), los atributos se convierten en el objeto de props, y el contenido se convierte en children. Las configuraciones antiguas compilaban a React.createElement(type, props, ...children), y por eso los archivos viejos empiezan con import React from 'react' aunque nunca mencionen React. La llamada devuelve un objeto simple llamado elemento de React. Puedes registrar uno en la consola:
La consola muestra que heading son solo datos: un tipo 'h3' y un objeto de props. Por eso también JSX se puede guardar en variables, pasar a funciones y devolver desde ellas.
JSX escapa el texto por ti
Cualquier cadena que pongas entre llaves se renderiza como texto, nunca como HTML. Si un usuario escribe <img src=x onerror=alert(1)> en una caja de comentarios, React muestra esos caracteres en pantalla en lugar de crear una etiqueta de imagen. Esto bloquea por defecto la forma más común de cross-site scripting (XSS).
El primer párrafo imprime las etiquetas como caracteres normales. El segundo usa dangerouslySetInnerHTML, que omite el escapado e inserta la cadena como HTML real, así que "our own" sale en negrita. El nombre largo es una advertencia: pasa solo HTML que generaste tú o que limpiaste con un sanitizador como DOMPurify. Pasar ahí la entrada del usuario vuelve a abrir el agujero de XSS que JSX cerró.
Preguntas frecuentes
¿Qué significa JSX?
JSX significa JavaScript XML. Es una extensión de sintaxis que te permite escribir marcado parecido a HTML dentro del código JavaScript.
¿JSX es HTML?
No. JSX se parece a HTML pero se compila a llamadas de función de JavaScript que crean elementos de React. Por eso usa className en lugar de class, nombres de atributos en camelCase y exige cerrar todas las etiquetas.
¿Puedo usar React sin JSX?
Sí. JSX es opcional: puedes llamar directamente a createElement('h1', { className: 'title' }, 'Hello') desde react. Casi todo el código de React usa JSX porque el marcado anidado es mucho más fácil de leer.
¿Por qué no puedo usar un if dentro de JSX?
Las llaves en JSX aceptan expresiones, cosas que producen un valor, y if es una sentencia. Usa un ternario (cond ? a : b), &&, o calcula el valor en una variable antes del return.
¿Cómo escribo un comentario en JSX?
Envuelve un comentario de JavaScript en llaves: {/* así */}. Los comentarios HTML (<!-- -->) son un error de sintaxis en JSX.