Invoker Commands ya es Baseline: los addEventListener de tus modales y menús ya son código muerto
webdevelopment 29 de septiembre de 2026 · Mintec

Invoker Commands ya es Baseline: los addEventListener de tus modales y menús ya son código muerto

La Invoker Commands API (commandfor + command) llegó a Baseline en diciembre de 2025 y permite abrir un diálogo o alternar un popover sin JavaScript. Aquí está el marco componente por componente para saber qué puedes borrar hoy, y los dos lugares donde lo nativo todavía pierde.

Invoker Commands ya es Baseline: los addEventListener de tus modales y menús ya son código muerto

Si tu modal, cajón, menú o tooltip todavía depende de un listener de JavaScript para abrirse, ese listener ya es código muerto. commandfor y command son Baseline — Chrome, Edge, Firefox y Safari los soportan desde diciembre de 2025 — y el navegador abrirá el diálogo, lo cerrará, moverá el foco y mantendrá aria-expanded sincronizado sin ejecutar una sola línea de tu script.

Esa es la respuesta directa. La parte interesante es lo que los equipos hacen con ella. Baseline no es un anuncio de funcionalidad: es una fecha límite para borrar. Cada mes que una feature soportada sigue envuelta en cableado artesanal, estás pagando mantenimiento, peso de bundle y riesgo de accesibilidad por algo que la plataforma ya posee.

Ya hicimos este argumento antes, en otra capa. Migramos proyectos lejos de los widgets ARIA porque el markup nativo le ganaba a los roles que estábamos inventando, y publicamos las lecciones cuando un equipo sobre-construyó su stack. La capa de cableado siempre fue la última trinchera, porque hasta ahora no existía una forma nativa de decir "este botón abre ese elemento". Esa brecha se cerró en diciembre.

Lo que realmente llegó

La Invoker Commands API agrega dos atributos a <button>:

<button type="button" commandfor="menu-sitio" command="show-modal">Menú</button>

<dialog id="menu-sitio">
  <button type="button" commandfor="menu-sitio" command="close">Cerrar</button>
  <nav><!-- ... --></nav>
</dialog>

Esa es toda la integración. La promoción a la capa superior, el atrapado del foco, la restauración del foco al cerrar, el manejo de Escape y los enlaces de accesibilidad vienen de <dialog> y del Popover API, que el botón ahora maneja de forma declarativa. El vocabulario incluido es pequeño y cerrado: show-modal, close y request-close para diálogos; show-popover, hide-popover y toggle-popover para popovers.

ComponenteStack nativoJavaScript que sobreviveVeredictoDiálogo modal<dialog> + commandfor="show-modal" + closedby="any"Ninguno para abrir, cerrar, fondo y EscapeBorra los listenersMenú popover, dropdown, tooltip[popover] + commandfor="toggle-popover"Ninguno para mostrar, ocultar y light-dismissBorra los listenersNavegación off-canvas<dialog> + invokersSolo el estado del enlace activoBorra la capa de abrir/cerrarAcordeón<details> (con name para un solo abierto)Ninguno para abrir y cerrarNativo, pero los invokers aún no lo alcanzanSelect / control de filtrosappearance: base-select (Customizable Select)Ninguno, donde está soportadoSolo mejora progresiva — Firefox todavía no llegóPestañas, control segmentado, carrusel, widget propioNo hay elemento nativoComportamiento, estado y tecladoMantén el script; borra solo los listeners de botón

Lee con cuidado la última fila. Los invoker commands no reemplazan la lógica del componente. Reemplazan el cableado entre un botón y aquello que el botón controla. Para un modal, el cableado era todo el trabajo, así que el trabajo desaparece. Para una lista de pestañas, el cableado era el 10% del trabajo y el otro 90% hay que escribirlo y auditarlo.

Los cuatro detalles que deciden si esto es una mejora o una regresión

La mayoría de los artículos se detiene en el ejemplo de código. Estos son los puntos que de verdad duelen en producción.

El evento command no burbujea. Se dispara directamente sobre el elemento nombrado por commandfor y no cruza límites de shadow DOM. Si estás acostumbrado a delegar listeners desde un contenedor, ese patrón deja de funcionar en silencio. Adjunta el listener al elemento objetivo.

Solo <button> puede ser un invoker. Los atributos y sus equivalentes IDL viven en HTMLButtonElement. Enlaces, inputs y elementos propios que envuelven un botón no reciben nada gratis: el botón nativo interno debe llevar los atributos.

Los comandos personalizados deben empezar con --. Ese prefijo está reservado, así que tu --expand o --copy nunca colisionará con un comando incluido que la especificación agregue más adelante. Un valor que no es incluido ni tiene prefijo -- es inválido y no dispara nada: un fallo silencioso que merece una prueba.

El polyfill no gestiona el estado ARIA de los comandos personalizados. El invokers-polyfill dispara el evento correctamente, pero para los comandos -- te deja aria-expanded y aria-pressed en manos tuyas. Los navegadores nativos los mantienen sincronizados en los incluidos. Es decir: un equipo que agrega el polyfill "por las dudas" puede terminar con un markup de accesibilidad menos correcto que la versión sin polyfill que reemplazó.

Vale la pena detenerse en ese último punto, porque invierte la cautela habitual. El propio repositorio modern-web-guidance de Google declara la fecha de Baseline como 2025-12-12 en un párrafo, y en el siguiente instruye al lector a que "MUST use polyfills as fallbacks" para invoker commands y popovers. Ambas afirmaciones están en el mismo documento. Cuando la guía de primera parte se contradice a sí misma, los equipos copian la mitad que leyeron primero — y el hábito de polyfillear todo de hace dos años es exactamente cómo un feature Baseline termina embarcando una regresión de accesibilidad encima.

Dónde lo nativo todavía pierde

Dos lugares, y conviene conocerlos antes de empezar a borrar.

Popover y <dialog> no son intercambiables. Un popover es ligero, se cierra al hacer clic fuera y no es modal; un diálogo es modal, atrapa el foco y vive en la capa superior. Elegir mal es un bug de accesibilidad, no una decisión de estilo. Scott O'Hara y Adrian Roselli han escrito extensamente sobre la semántica real que cada uno te da — léelos antes de convertir un tooltip en un modal porque show-modal parecía cómodo.

No todo llegó a Baseline el mismo día. Customizable Select se publicó en Chrome y Edge 135 y llegó en Safari 27, pero Firefox sigue experimental. Ya escribimos lo que eso implica para un design system — se estiliza detrás de @supports y el fallback sin estilos sigue siendo un <select> funcional. Mejora progresiva, no un reemplazo directo.

También hay una rareza del foco que conviene probar: en algunas versiones de WebKit, showModal() deja el anillo de foco visible en el primer elemento para quienes usan el ratón, y los clientes lo notan. Prueba con un trackpad real antes de desplegar.

Cómo corremos la auditoría

El flujo es aburrido, y funciona:

  1. Inventario de todos los elementos con un handler de click adjunto con fines de mostrar/ocultar — disparadores de modal, alternadores de menú, aperturas de tooltip, aperturas de cajón.
  2. Sepáralos en "abre o cierra algo nativo" y "hace otra cosa". El paso uno suele matar dos tercios de la lista.
  3. Para los sobrevivientes, confirma que el objetivo sea un <dialog> o que tenga popover. Si es un <div> con position: fixed, tienes una migración más grande que la que cubre este artículo.
  4. Reemplaza el listener por commandfor + command. Agrega type="button" para que el botón nunca envíe un formulario por accidente.
  5. Revisa qué JavaScript queda. Si es cero, borra el handler y también el import del polyfill.
  6. Prueba solo con teclado: Tab para entrar, Enter, Escape, retorno del foco. Si alguno de esos era trabajo de tu script, ahora es trabajo del navegador — confirma que lo está haciendo.

La razón para correr esto ahora y no el próximo trimestre no es orden. Los navegadores pasaron a ciclos de lanzamiento más cortos este año — cubrimos el ciclo de dos semanas de Chrome cuando llegó — y esa misma cadencia aplica a las features de la plataforma de abajo. La brecha entre "la especificación existe" y "los navegadores de tus usuarios la tienen" es más corta que nunca, lo que significa que la brecha entre "es Baseline" y "igual embarcamos un polyfill" es puro desperdicio.

Lo que viene

El soporte de <details> para los invoker commands sigue en el roadmap y no en la especificación, así que el botón de abrir de un acordeón sigue siendo HTML nativo pero todavía no conectado de forma declarativa. La propuesta hermana, interestfor, apunta a comportamientos disparados por hover y foco — tooltips que funcionan sin script — y no es Baseline.

Ninguna de las dos cambia la conclusión. La capa de modales y menús, que es donde la mayoría de los sitios guarda la mayor cantidad de listeners duplicados, está terminada. La pregunta es si tu codebase lo refleja.

Preguntas Frecuentes

¿Qué es la Invoker Commands API?

Es un par de atributos HTML, commandfor y command, que se agregan al elemento button. commandfor apunta al elemento que el botón controla y command nombra la acción a ejecutar, como show-modal, close, request-close, show-popover, hide-popover o toggle-popover. El navegador ejecuta la acción, gestiona el foco y mantiene sincronizado el estado de accesibilidad, así que no se necesita ningún listener para las acciones incluidas.

¿La Invoker Commands API funciona en todos los navegadores?

Sí. Está disponible como Baseline Newly available desde el 12 de diciembre de 2025: Chrome y Edge 135, Firefox 144 y Safari 26.2 la incluyen. Un polyfill solo se justifica para audiencias con navegadores anteriores a esas versiones, y el polyfill más popular no mantiene el estado ARIA de los comandos personalizados, así que usarlo puede costarte accesibilidad en lugar de protegerte.

¿Cuándo debe un componente seguir usando JavaScript en lugar de invoker commands?

Cuando el comportamiento no tiene un comando incluido. Pestañas, controles segmentados, carruseles y widgets personalizados todavía necesitan script, porque la especificación no define cambios de estado para ellos. Los invoker commands ayudan ahí también, pero solo como cableado: tu script se mantiene, los listeners de los botones no.

Artículos Relacionados