JSX y TSX
Escribe UI declarativa usando expresiones de JavaScript que parecen HTML - con soporte completo de TypeScript.
Busca en todas las páginas de la documentación
Escribe UI declarativa usando expresiones de JavaScript que parecen HTML - con soporte completo de TypeScript.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
Tarjeta de referencia rápida - lista para copiar y pegar.
// Expresión JSX
const element = <h1 className="title">Hola, {name}</h1>
// Fragmento (sin nodo DOM adicional)
const list = (
<>
<dt>Término</dt>
<dd>Definición</dd>
</>
)
// Espacio para expresión - cualquier expresión JS válida funciona dentro de { }
<p>{isLoggedIn ? `Bienvenido, ${user.name}` : "Por favor inicia sesión"}</p>
// Propagar props
<Button {...props} />Cuándo recurrir a esto: Todo componente de React devuelve JSX. Entender las reglas ahorra horas de depuración.
"use client";
import { useState } from "react";
interface UserCardProps {
name: string;
role: "admin" | "editor" | "viewer";
avatarUrl?: string;
}
export function UserCard({ name, role, avatarUrl }: UserCardProps) {
const [expanded, setExpanded] = useState(false);
const roleBadge: Record<string, string> = {
admin: "bg-red-100 text-red-800",
editor: "bg-blue-100 text-blue-800",
viewer: "bg-gray-100 text-gray-800",
};
return (
<article className="rounded-lg border p-4">
<div className="flex items-center gap-3">
{avatarUrl ? (
<img
src={avatarUrl}
alt={`avatar de ${name}`}
className="h-10 w-10 rounded-full"
/>
) : (
<div className="flex h-10 w-10 items-center justify-center rounded-full bg-gray-200">
{name[0]}
</div>
)}
<div>
<h2 className="font-semibold">{name}</h2>
<span className={`rounded px-2 py-0.5 text-xs ${roleBadge[role]}`}>
{role}
</span>
</div>
</div>
{expanded && (
<p className="mt-3 text-sm text-gray-600">
{name} tiene permisos de <strong>{role}</strong> en este espacio de trabajo.
</p>
)}
<button
onClick={() => setExpanded(prev => !prev)}
className="mt-2 text-sm text-blue-600 underline"
>
{expanded ? "Ver menos" : "Ver más"}
</button>
</article>
);
}Qué demuestra esto:
className dinámico usando plantillas literales<div className="x"> se compila a React.createElement("div", { className: "x" }) (o a la transformación JSX moderna que importa jsx desde react/jsx-runtime automáticamente)<>...</> (Fragment) cuando no quieras un envoltorio adicional en el DOM{ } crean un espacio para expresión - funciona cualquier cosa que produzca un valor: variables, ternarias, llamadas a funciones, métodos de arreglos.tsx y admite la verificación de tipos de TypeScript para props, expresiones y manejadores de eventos| Regla | Correcto | Incorrecto |
|---|---|---|
class de HTML | className | class |
for de HTML | htmlFor | for |
| Etiquetas autocerradas | <img /> | <img> |
| Prop style | style={{ color: "red" }} | style="color:red" |
| Atributos booleanos | <input disabled /> | <input disabled="true"> |
| Atributos de datos | data-testid="x" | Funciona tal cual |
// Fragmento con nombre (cuando necesitas una key)
import { Fragment } from "react";
{items.map(item => (
<Fragment key={item.id}>
<dt>{item.term}</dt>
<dd>{item.definition}</dd>
</Fragment>
))}
// Sintaxis corta (no se necesita key)
<>
<Header />
<Main />
<Footer />
</>// React.ReactNode - el tipo de retorno más amplio
function Wrapper({ children }: { children: React.ReactNode }) {
return <section>{children}</section>;
}
// React.JSX.Element - un único elemento JSX
function Badge(): React.JSX.Element {
return <span>OK</span>;
}
// Componentes genéricos
function List<T>({ items, render }: { items: T[]; render: (item: T) => React.ReactNode }) {
return <ul>{items.map((item, i) => <li key={i}>{render(item)}</li>)}</ul>;
}class vs className - Usar class en JSX compila pero genera una advertencia en la consola y no aplicará los estilos correctamente en algunos entornos. Solución: Usa siempre className.
Elementos adyacentes sin un envoltorio - Devolver <h1/><p/> sin un elemento padre es un error de sintaxis. Solución: Envuélvelos en un Fragment <>...</> o en un <div>.
Renderizar objetos - {user} lanza "Objects are not valid as a React child" si user es un objeto. Solución: Renderiza una propiedad específica como {user.name}.
Colapso de espacios en blanco - JSX colapsa los espacios en blanco de forma más agresiva que HTML. Dos elementos en línea como <span>A</span><span>B</span> no tendrán espacio entre ellos. Solución: Añade {" "} entre ellos o usa gap con CSS.
Comentarios en JSX - Los comentarios de HTML <!-- --> no funcionan. Solución: Usa {/* comentario */} dentro de JSX.
| Alternativa | Úsala cuando | No la uses cuando |
|---|---|---|
| Plantillas literales (etiquetadas) | Construyes HTML de correo o cadenas estáticas del lado del servidor | Necesitas interactividad o características de React |
React.createElement | Construyes elementos programáticamente en un bucle sin JSX | Importa la legibilidad (JSX casi siempre es más claro) |
| MDX | Escribes páginas con mucho contenido que mezclan Markdown y componentes | Construyes UI de aplicación interactiva |
TSX es JSX dentro de archivos .tsx con la verificación de tipos de TypeScript habilitada. La sintaxis es idéntica, pero TSX valida los tipos de las props, los tipos de las expresiones y los tipos de los manejadores de eventos en tiempo de compilación.
class es una palabra reservada en JavaScript. JSX se compila a llamadas de función de JavaScript, por lo que React usa className para evitar el conflicto. Usar class genera una advertencia en la consola.
Cualquier expresión de JavaScript válida - variables, ternarias, llamadas a funciones, plantillas literales y métodos de arreglos como .map(). Las sentencias como if/else o los bucles for no pueden ir directamente dentro de {}.
Usa <>...</> cuando necesites devolver varios elementos hermanos sin añadir un nodo DOM adicional. Usa <Fragment key={...}> cuando recorras una lista que necesita keys en el envoltorio.
La prop style acepta un objeto de JavaScript con propiedades en camelCase, no una cadena CSS:
<div style={{ backgroundColor: "red", fontSize: 16 }} />No directamente. Usa una expresión ternaria {condition ? <A /> : <B />} o extrae la lógica a una variable antes de la sentencia return.
<Button {...props} /> pasa todas las propiedades del objeto props como atributos individuales al componente. Esto es útil para reenviar props o extender elementos HTML nativos.
Usa {/* comentario */} dentro de JSX. Los comentarios al estilo HTML <!-- --> no funcionan y provocarán un error de sintaxis.
React.ReactNode es el tipo más amplio - incluye JSX, cadenas, números, null, undefined y arreglosReact.JSX.Element es únicamente un elemento JSX, sin cadenas ni nullReactNode para las props children y JSX.Element para tipos de retorno de funciones que siempre devuelven JSXLas expresiones JSX se compilan a una única llamada de función como React.createElement(...). Varios elementos adyacentes serían varios valores de retorno, algo que JavaScript no admite. Envuelve los hermanos en un Fragment o en un elemento contenedor.
Usa dangerouslySetInnerHTML={{ __html: htmlString }}. Úsalo únicamente con contenido saneado y de confianza - omite las protecciones XSS de React.
No renderizan nada. Por eso funciona {condition && <Component />} - cuando condition es false, false se renderiza como vacío. Sin embargo, 0 se renderiza como el texto "0".
Revisado por Chris St. John·Última actualización: 16 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥