Inicio / Artículos

Seis características nativas de HTML que reemplazan a las bibliotecas comunes de interfaz de usuario en JavaScript

Aprenda cómo los elementos popover, detalles exclusivos, diálogos, Declarative Shadow DOM, fetchpriority y datalist reemplazan al JavaScript personalizado, además de los límites que cada uno sigue teniendo.

Editor: REACTAPP.TOP6 min de lectura1277 palabras

Fuentes: HTML Features in 2026 That Most Devs Don’t Know Exist

Durante años, HTML proporcionaba la estructura y JavaScript se encargaba de todo el comportamiento: un modal requería una biblioteca de React, una herramienta de ayuda necesitaba Popper.js o Tippy, y los componentes generados en el servidor exigían scripts personalizados. Mientras tanto, el estándar vivo HTML de WHATWG y los motores de navegador añadieron bloques de construcción nativos que cubren muchos de esos casos con solo unos pocos atributos, reduciendo el código genérico y el tamaño del paquete, además de garantizar la accesibilidad por defecto. Esta guía aborda seis de ellos, el marcado necesario para cada uno y los casos en los que aún se requiere CSS o JavaScript. Asegúrese de verificar la compatibilidad del navegador con su público antes de implementar soluciones alternativas.

1. Ventanas emergentes con el atributo popover

Los tooltips y menús solían requerir lidiar con los contextos de apilamiento z-index y escribir manualmente los listeners para detectar clics fuera del elemento. Con la API Popover, cualquier elemento que contenga el atributo popover es elevado a la capa superior al abrirse, por encima de todo el contenido normal, independientemente del z-index. Un botón cuyo atributo popovertarget indique el id del elemento lo activa:

<!-- The Trigger -->
<button popovertarget="my-menu">Toggle Menu</button>

<!-- The Popover Content -->
<div id="my-menu" popover>
  <p>I am natively managed! Press ESC or click outside to close me.</p>
</div>

Sin necesidad de JavaScript se obtiene lo siguiente:

  • Activación declarativa: el botón abre y cierra el popover.
  • Cierre sencillo: hacer clic fuera del elemento o presionar Escape lo cierra. Esto aplica al modo predeterminado popover="auto"; con popover="manual" el cierre queda a tu cargo.
  • Sin conflictos de apilamiento: el popover abierto se muestra en la capa superior, por encima de todo lo demás.

Dos limitaciones: la API controla la visibilidad y el apilamiento, pero no la ubicación; por lo tanto, anclar un menú a su desencadenante sigue requiriendo CSS (posicionamiento clásico o el más reciente, pero menos compatible, de posicionamiento por anclaje). Además, un popover no es modal y no atrapa el foco, así que use dialog para las confirmaciones.

2. Acordeones exclusivos con detalles y nombre

details y summary han permitido durante mucho tiempo secciones plegables sin JavaScript. La novedad reciente es que los elementos details que comparten un name forman un grupo en el cual solo uno puede estar abierto, al igual que un acordeón clásico.

<details name="faq">
  <summary>What is modern HTML?</summary>
  <p>A living standard evolving directly inside browser engines.</p>
</details>

<details name="faq">
  <summary>Do I still need JavaScript?</summary>
  <p>Much less of it than you used to!</p>
</details>

<details name="faq">
  <summary>Is this supported natively?</summary>
  <p>Yes, across all major modern browser engines.</p>
</details>

Al abrir una pregunta, se cierra cualquier otro elemento abierto con name="faq", sin necesidad de listeners, hooks de estado ni cambio de clases. Los navegadores que no admiten name simplemente permiten varios elementos abiertos, lo cual constituye una solución de retroceso elegante.

3. Modales accesibles con dialog y ::backdrop

Las superposiciones personalizadas con div suelen fallar en las auditorías de accesibilidad, ya que un modal correcto debe mantener el foco dentro de sí, bloquear la página que se encuentra detrás y restaurar el foco en el elemento desencadenante posteriormente. El elemento dialog se encarga de esto. A continuación, un formulario con method="dialog" cierra el diálogo al hacer clic en cualquiera de los botones, y el value del botón presionado se convierte en el returnValue del diálogo:

<dialog id="user-modal">
  <h2>Confirm Action</h2>
  <p>Are you sure you want to delete this repository?</p>

  <!-- A form inside a dialog with method="dialog" closes it automatically -->
  <form method="dialog">
    <button value="cancel">Cancel</button>
    <button value="confirm">Delete</button>
  </form>
</dialog>

<button onclick="document.getElementById('user-modal').showModal()">
  Open Modal
</button>

La superposición atenuada es el pseudo-elemento ::backdrop, estilizado con CSS estándar:

/* Styling the native browser backdrop */
dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
}

showModal() coloca el diálogo en la capa superior, inactiva el resto de la página, mantiene el foco dentro y permite usar la tecla Escape para cerrarlo; al cerrarse, los navegadores actuales devuelven el foco al elemento que estaba seleccionado anteriormente. Por el contrario, show() lo abre de forma no modal sin esas protecciones. En React, se debe llamar a showModal() a través de un ref en lugar de usar un onclick inline.

4. Componentes Web generados en el servidor con Shadow DOM declarativo

Anteriormente, Shadow DOM requería JavaScript del lado del cliente (element.attachShadow({ mode: 'open' })), por lo que los Componentes Web generados en el servidor o estáticamente no tenían marcado encapsulado hasta que se ejecutaban los scripts, lo que causaba cambios repentinos en el diseño y sin estilos. Shadow DOM declarativo soluciona este problema: un template con shadowrootmode dentro del elemento anfitrión describe el árbol de sombra en HTML:

<user-card>
  <template shadowrootmode="open">
    <style>
      /* Styles here stay encapsulated inside this component */
      h3 { color: #3b82f6; font-family: sans-serif; }
    </style>

    <h3>Jane Doe</h3>
    <p>Senior Frontend Engineer</p>
  </template>
</user-card>

El analizador convierte la plantilla en una raíz sombra en user-card antes de renderizar, de modo que los estilos y el marcado con ámbito específico se muestran en la primera pintura. Precaución: esto solo ocurre durante el análisis del HTML. El marcado insertado posteriormente mediante innerHTML no crea ninguna raíz sombra; la inserción dinámica requiere APIs como setHTMLUnsafe(), por lo que hay que verificar la compatibilidad actual.

5. Priorizar recursos críticos con fetchpriority

loading="lazy" y async/defer no permiten indicar cuáles recursos iniciales son los más importantes. Cuando hay varias imágenes arriba en la página, la imagen principal detrás de tu Largest Contentful Paint (LCP) debe tener prioridad sobre insignias e íconos. fetchpriority proporciona esa indicación al programador de red:

<!-- Critical LCP Image: Load this immediately! -->
<img src="hero-banner.webp" fetchpriority="high" alt="Product Hero">

<!-- Lower priority images -->
<img src="avatar.webp" fetchpriority="low" alt="User avatar">

<!-- Critical JavaScript bundle -->
<script src="app.js" fetchpriority="high"></script>

Esto puede mejorar los Core Web Vitals sin tocar la lógica de la aplicación. Se trata de una sugerencia, no de una orden, y marcar muchos recursos como high anula el beneficio. Además, nunca cargue de forma diferida la imagen LCP.

6. Sugerencias nativas con datalist

Muchos proyectos añaden un componente de autocompletado complejo solo para sugerir valores mientras permiten texto libre. datalist hace esto de forma nativa: úncelo mediante el atributo list del elemento de entrada y sus opciones se convertirán en sugerencias.

<label for="framework">Choose or type a framework:</label>
<input list="frameworks" id="framework" name="framework" placeholder="e.g. Next.js">

<datalist id="frameworks">
  <option value="Next.js"></option>
  <option value="SvelteKit"></option>
  <option value="Nuxt.js"></option>
  <option value="Astro"></option>
  <option value="Remix"></option>
</datalist>

El navegador renderiza y filtra la lista, gestiona la navegación por teclado y sigue el aspecto de la plataforma. El compromiso es el control: el estilo es mínimo, el comportamiento difiere entre navegadores y dispositivos móviles, y no es posible tener opciones avanzadas. Es ideal para campos simples de “seleccionar o escribir”; un combobox con marca comercial aún necesita un componente.

Funcionalidad nativa frente al enfoque anterior

  • Indicadores de herramientas y menús: popover en lugar de una biblioteca de posicionamiento, además de manejo de clics fuera del elemento y tecla Escape (la posición sigue proveniendo de CSS).
  • Acordeones: elementos details que comparten un name en lugar de lógica de estado y alternancia en JavaScript.
  • Modales: dialog con showModal() y ::backdrop en lugar de una superposición personalizada con gestión manual del foco.
  • Componentes generados por servidor encapsulados: template shadowrootmode en lugar de llamadas a attachShadow() exclusivas para el cliente.
  • Prioridades de carga: fetchpriority en lugar de trucos manuales de precarga o orden de carga controlado por scripts.
  • Sugerencias de entrada: datalist en lugar de un widget de autocompletado personalizado para casos simples.
  • Para conocer más sobre las funciones de la plataforma que pueden reemplazar dependencias, consulte nuestro resumen de APIs nativas del navegador que reemplazan a paquetes populares de npm.

    Puntos clave

    • Los navegadores ahora incluyen funcionalidades que antes requerían bibliotecas, a menudo con manejo de enfoque y opción para cerrar con la tecla Escape integradas.
    • Lo nativo no significa completo: los popovers necesitan CSS para su posicionamiento, datalist ofrece pocos estilos, y el Declarative Shadow DOM solo funciona en el momento del análisis.
    • Antes de agregar una dependencia de interfaz de usuario, verifique si un elemento o atributo ya cubre la necesidad real en los navegadores que soporta.

    Lecturas relacionadas

  • Siete características nativas de JavaScript que reemplazan las dependencias de utilidades — Cómo Temporal, mediante declaraciones, inserciones en Map, Math.sumPrecise, ayudantes de iterador, métodos de Set y Promise.withResolvers eliminan el código genérico común en JavaScript.
  • De la sopa de divs a un markup significativo: Una guía práctica de HTML semántico — Aprenda por qué los divs genéricos dañan la accesibilidad, el rastreo y la mantenibilidad, qué elementos semánticos usar en su lugar, y cómo refactorizar un componente de tarjeta real.