HTML a JSX

className, htmlFor, estilos en objeto, comentarios y void tags. Ideal para pegar plantillas HTML en React.

{{ t("htmlToJsxHint") }}

{{ htmlToJsx.message }}

Descripción

React fue creado por Jordan Walke en Facebook en 2011, presentado internamente como FaxJS y lanzado al público en JSConf en mayo de 2013. La reacción inicial de la comunidad fue de escepticismo y, en muchos casos, rechazo abierto. JSX — la sintaxis que mezcla HTML dentro de JavaScript — parecía una herejía. Separar HTML, CSS y JavaScript en archivos distintos era un principio casi sagrado del desarrollo web desde los años 2000. Poner marcado dentro de funciones JavaScript parecía un paso atrás respecto a décadas de buenas prácticas.

El cambio de opinión fue rápido. Tras unos pocos meses con React en producción, la mayoría de los desarrolladores concluyó que separar HTML de JS era una separación de tecnologías, no de responsabilidades reales. Un componente de botón tiene marcado, estilo y comportamiento, y tenerlo todo en un único archivo de componente hacía el código más fácil de mantener que tres archivos separados en sincronía. JSX ganó el debate pragmático. Hoy es raro encontrar un proyecto React sin JSX como estándar, y el formato ha influido en Solid.js, Preact, Qwik y otros frameworks.

El conversor de esta página resuelve el problema práctico de migrar plantillas HTML existentes a JSX. Los cambios son sistemáticos: `class` se convierte en `className` (porque `class` es una palabra reservada en JavaScript), `for` en labels pasa a `htmlFor`, los atributos con varias palabras como `tabindex` y `maxlength` pasan a camelCase (`tabIndex`, `maxLength`), los estilos inline pasan de cadena a objeto JavaScript, los comentarios HTML se convierten en expresiones JSX y las void tags como `<img>` reciben cierre explícito `<img />` porque JSX sigue las reglas de XML bien formado.

Detalle técnico

Por qué JSX pareció una herejía y por qué ganó de todas formas

  • Antes de JSX, construir interfaces con React puro requería llamadas anidadas a `React.createElement('div', {className: 'container'}, React.createElement('h1', null, 'Título'))`. Funcionalmente correcto, pero completamente ilegible para cualquier cosa más allá de un componente trivial. JSX fue creado como azúcar sintáctico que Babel compila en esas llamadas, pero la DX (experiencia del desarrollador) es radicalmente diferente.
  • Vue, Angular y Svelte tomaron caminos distintos: Vue usa plantillas similares a HTML con directivas (`v-if`, `v-for`), Angular usa plantillas con su propia sintaxis y Svelte compila a JavaScript puro. JSX es el enfoque más cercano a 'JavaScript puro con extensión sintáctica', lo que tanto atrae a los desarrolladores JS como incomoda a los diseñadores acostumbrados al HTML plano.
  • La reinterpretación de la 'separación de responsabilidades' fue el argumento que cambió el debate. El principio original (HTML/CSS/JS en archivos separados) separaba tecnologías, no responsabilidades de producto. Un componente de modal tiene lógica, estilo y marcado que cambian juntos: separarlos en archivos distintos solo crea acoplamiento a distancia.
  • JSX no es exclusivo de React. Solid.js usa JSX pero compila de forma diferente (sin Virtual DOM). Preact es una alternativa a React con JSX compatible y solo 3 KB de tamaño. Qwik usa JSX con serialización de estado para hidratación parcial. Stencil.js usa JSX para web components nativos.
  • Babel transforma JSX a JavaScript antes de cualquier ejecución. El compilador moderno de React (React 17+) ya no requiere importar React explícitamente en cada archivo JSX: la transformación es automática. TypeScript también admite JSX de forma nativa con archivos `.tsx`.

Las reglas de conversión HTML → JSX: un mapeo sistemático

  • `class` → `className`: `class` es una palabra reservada en JavaScript para definir clases ES6. En JSX el atributo correspondiente es `className`. Olvidar esta conversión es el error más común al migrar plantillas.
  • `for` → `htmlFor`: El atributo `for` en `<label>` también es una palabra reservada (el bucle `for` de JavaScript). En JSX es `htmlFor`. Del mismo modo, `<input type="text">` sin atributos problemáticos no cambia.
  • Atributos en camelCase: `tabindex` → `tabIndex`, `maxlength` → `maxLength`, `readonly` → `readOnly`, `autofocus` → `autoFocus`, `crossorigin` → `crossOrigin`, `enctype` → `encType`. La regla: si el atributo HTML tiene guion o es una palabra compuesta con casing inconsistente, en JSX se usa camelCase.
  • Estilos inline: `style="color: red; font-size: 16px"` → `style={{ color: 'red', fontSize: '16px' }}`. Las propiedades CSS con guion pasan a camelCase. Los valores son cadenas (salvo los números sin unidad, como `zIndex: 10`). Nota las llaves dobles: la exterior `{}` es la interpolación JSX, la interior `{}` es el objeto JavaScript.
  • Void tags con cierre explícito: `<img>`, `<input>`, `<br>`, `<hr>`, `<meta>`, `<link>` en HTML5 no necesitan cierre. En JSX, que sigue las reglas de XML bien formado, todas las etiquetas deben cerrarse: `<img />`, `<input />`, `<br />`. Sin esto, Babel lanza un error de parseo.

Fragmentos de Código

Tabla de conversión HTML → JSX
// ATRIBUTOS: HTML → JSX
// class="container"         → className="container"
// for="input-id"            → htmlFor="input-id"
// tabindex="0"              → tabIndex={0}
// maxlength="100"           → maxLength={100}
// readonly                  → readOnly
// autofocus                 → autoFocus

// ESTILOS INLINE:
// style="color:red"         → style={{ color: 'red' }}
// style="font-size:16px"    → style={{ fontSize: '16px' }}
// style="background-color"  → style={{ backgroundColor: '...' }}

// COMENTARIOS:
// <!-- comentario HTML -->   → {/* comentario JSX */}

// VOID TAGS:
// <img src="x.png">         → <img src="x.png" />
// <input type="text">       → <input type="text" />
// <br>                      → <br />
Card Bootstrap → Componente React
// HTML original (Bootstrap card)
// <div class="card" style="width: 18rem;">
//   <img src="img.jpg" class="card-img-top" alt="Descripción">
//   <div class="card-body">
//     <h5 class="card-title">Título del Card</h5>
//     <p class="card-text">Texto descriptivo.</p>
//     <a href="#" class="btn btn-primary">Acción</a>
//   </div>
// </div>

function Card({ imagen, alt, titulo, texto, href }) {
  return (
    <div className="card" style={{ width: '18rem' }}>
      <img src={imagen} className="card-img-top" alt={alt} />
      <div className="card-body">
        <h5 className="card-title">{titulo}</h5>
        <p className="card-text">{texto}</p>
        <a href={href} className="btn btn-primary">
          Acción
        </a>
      </div>
    </div>
  );
}

Ejemplo

<div class="box" tabindex="0">
  <img src="/a.png" alt="">
  <!-- ok -->
</div>

Preguntas frecuentes

¿Para qué sirve esta herramienta?

Funciona por completo en tu navegador: sirve para validar, formatear o convertir datos en el día a día.

¿Se envían mis datos a algún servidor?

El procesamiento es local con JavaScript. No almacenamos lo que pegas en los campos de texto.

¿Puedo usarlo con datos reales en producción?

Úsalo bajo tu responsabilidad. Para secretos (contraseñas, tokens), prefiere entornos controlados y políticas internas. Recuerda de revisar los contenidos generados. Nunca confies ciegamente en cosas que ves en internet.