JSX y TSX
Escribe UI declarativa usando expresiones de JavaScript que parecen HTML — con soporte completo de TypeScript.
Receta
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.
Ejemplo práctico
"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:
- Renderizado condicional con expresiones ternarias dentro de JSX
classNamedinámico usando plantillas literales- Espacios para expresiones con valores calculados
- Interfaz de TypeScript para las props del componente
Análisis en profundidad
Cómo funciona
- JSX es azúcar sintáctico —
<div className="x">se compila aReact.createElement("div", { className: "x" })(o a la transformación JSX moderna que importajsxdesdereact/jsx-runtimeautomáticamente) - Toda expresión JSX debe devolver un único elemento raíz — usa
<>...</>(Fragment) cuando no quieras un envoltorio adicional en el DOM - Las llaves
{ }crean un espacio para expresión — funciona cualquier cosa que produzca un valor: variables, ternarias, llamadas a funciones, métodos de arreglos - TSX es idéntico a JSX pero vive en archivos
.tsxy admite la verificación de tipos de TypeScript para props, expresiones y manejadores de eventos
Reglas de JSX de un vistazo
| 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 |
Fragmentos
// 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 />
</>Notas de TypeScript
// 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>;
}Trampas comunes
-
classvsclassName— Usarclassen JSX compila pero genera una advertencia en la consola y no aplicará los estilos correctamente en algunos entornos. Solución: Usa siempreclassName. -
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" siuseres 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.
Alternativas
| 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 |
Preguntas frecuentes
¿Cuál es la diferencia entre JSX y TSX?
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.
¿Por qué tengo que usar className en vez de class?
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.
¿Qué puede ir dentro de las llaves en JSX?
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 {}.
¿Cuándo debería usar un Fragment en vez de un div?
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.
¿Cómo funciona la prop style en JSX?
La prop style acepta un objeto de JavaScript con propiedades en camelCase, no una cadena CSS:
<div style={{ backgroundColor: "red", fontSize: 16 }} />¿Puedo usar if/else dentro de JSX?
No directamente. Usa una expresión ternaria {condition ? <A /> : <B />} o extrae la lógica a una variable antes de la sentencia return.
¿Qué hace el operador de propagación en un elemento JSX?
<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.
¿Cómo escribo comentarios dentro de JSX?
Usa {/* comentario */} dentro de JSX. Los comentarios al estilo HTML <!-- --> no funcionan y provocarán un error de sintaxis.
¿Qué es React.ReactNode vs React.JSX.Element?
React.ReactNodees el tipo más amplio — incluye JSX, cadenas, números,null,undefinedy arreglosReact.JSX.Elementes únicamente un elemento JSX, sin cadenas ni null- Usa
ReactNodepara las propschildrenyJSX.Elementpara tipos de retorno de funciones que siempre devuelven JSX
¿Por qué JSX requiere un único elemento raíz?
Las 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.
¿Cómo renderizo cadenas de HTML sin procesar en JSX?
Usa dangerouslySetInnerHTML={{ __html: htmlString }}. Úsalo únicamente con contenido saneado y de confianza — omite las protecciones XSS de React.
¿Qué ocurre cuando renderizo false, null o undefined en JSX?
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".
Relacionado
- Componentes — bloques de construcción que devuelven JSX
- Renderizado condicional — patrones para mostrar/ocultar JSX
- Listas y keys — renderizado de arreglos de elementos JSX