4 puntos por GN⁺ 2025-03-08 | 1 comentarios | Compartir por WhatsApp
  • Los botones son esenciales para crear aplicaciones web dinámicas. Se usan para abrir menús, cambiar acciones y enviar formularios
  • En Chrome 135, los nuevos atributos command y commandfor mejoran y reemplazan los atributos anteriores popovertargetaction y popovertarget
  • Problemas que suelen aparecer al implementar el comportamiento de botones:
    • Los manejadores onclick de HTML pueden tener un uso limitado en código real debido a políticas de seguridad (CSP)
    • Es necesario sincronizar el estado entre el botón y otros elementos, y el código para gestionar ese estado manteniendo la accesibilidad es complejo
    • Incluso en React, AlpineJS y Svelte, el manejo de estado y eventos también es complejo

Patrón command y commandfor

  • Al usar los atributos command y commandfor, un botón puede actuar de forma declarativa sobre otro elemento. Esto ofrece la comodidad de un framework sin perder flexibilidad
  • El botón commandfor usa un ID (similar al atributo for) y command acepta valores integrados para ofrecer un enfoque más intuitivo
  • Ejemplo: implementar un botón para abrir un menú
    • No se necesitan aria-expanded ni JavaScript adicional
    <button commandfor="my-menu" command="show-popover">  
      Open Menu  
    </button>  
    <div popover id="my-menu">  
      <!-- ... -->  
    </div>  
    

command y commandfor vs popovertargetaction y popovertarget

  • Si ya usaste popover, puede que conozcas los atributos popovertarget y popovertargetaction
  • Funcionan de forma similar a commandfor y command, pero están especializados para popovers
  • Los nuevos atributos reemplazan por completo a los anteriores y además ofrecen funcionalidad adicional

Comandos integrados

  • El atributo command incorpora acciones que se mapean a varias API
    • show-popover: se mapea a el.showPopover()
    • hide-popover: se mapea a el.hidePopover()
    • toggle-popover: se mapea a el.togglePopover()
    • show-modal: se mapea a dialogEl.showModal()
    • close: se mapea a dialogEl.close()
  • Ejemplo: implementar un diálogo de confirmación de borrado
    • Es posible gestionar el estado y la accesibilidad sin JavaScript
    <button commandfor="confirm-dialog" command="show-modal">  
      Delete Record  
    </button>  
    <dialog id="confirm-dialog">  
      <header>  
        <h1>Delete Record?</h1>  
        <button commandfor="confirm-dialog" command="close" aria-label="Close">  
          <img role="none" src="/close-icon.svg">  
        </button>  
      </header>  
      <p>Are you sure? This action cannot be undone</p>  
      <footer>  
        <button commandfor="confirm-dialog" command="close" value="cancel">  
          Cancel  
        </button>  
        <button commandfor="confirm-dialog" command="close" value="delete">  
          Delete  
        </button>  
      </footer>  
    </dialog>  
    
    • Código para procesar el resultado: se puede manejar el valor devuelto en el evento close del diálogo
    dialog.addEventListener("close", (event) => {  
      if (event.target.returnValue === "cancel") {  
        console.log("Cancel was clicked");  
      } else if (event.target.returnValue === "delete") {  
        console.log("Delete was clicked");  
      }  
    });  
    

Comandos personalizados

  • Además de los comandos integrados, se pueden definir comandos personalizados usando el prefijo --
  • Los comandos personalizados disparan el evento "command" en el elemento objetivo, pero no ejecutan lógica adicional
  • Ejemplo: implementar un comando para rotar una imagen
    <button commandfor="the-image" command="--rotate-landscape">  
      Landscape  
    </button>  
    <button commandfor="the-image" command="--rotate-portrait">  
      Portrait  
    </button>  
    <img id="the-image" src="photo.jpg">  
    
    <script type="module">  
      const image = document.getElementById("the-image");  
      image.addEventListener("command", (event) => {  
        if (event.command === "--rotate-landscape") {  
          image.style.rotate = "-90deg";  
        } else if (event.command === "--rotate-portrait") {  
          image.style.rotate = "0deg";  
        }  
      });  
    </script>  
    

Manejo de comandos en Shadow DOM

  • En Shadow DOM, como commandfor funciona con base en ID, existen las siguientes limitaciones:
    • No es posible referenciar elementos entre distintos Shadow DOM
    • En estos casos, se puede usar la API de JavaScript para establecer la propiedad .commandForElement
  • Ejemplo: conectar un comando en Shadow DOM
    <my-element>  
      <template shadowrootmode="open">  
        <button command="show-popover">Show popover</button>  
        <slot></slot>  
      </template>  
      <div popover><!-- ... --></div>  
    </my-element>  
    
    <script>  
      customElements.define("my-element", class extends HTMLElement {  
        connectedCallback() {  
          const popover = this.querySelector('[popover]');  
          this.shadowRoot.querySelector('button').commandForElement = popover;  
        }  
      });  
    </script>  
    

Planes futuros

  • En Chrome planean agregar más comandos integrados:
    • abrir y cerrar elementos <details>
    • soporte del comando show-picker en <input> y <select>
    • comandos de reproducción para <video> y <audio>
    • función para copiar texto desde un elemento

1 comentarios

 
GN⁺ 2025-03-08
Opiniones de Hacker News
  • Los teóricos de los lenguajes de programación han estado especulando desde los años 80 sobre comefrom, una versión más potente de goto. Solo se implementó en INTERCAL. INTERCAL es superior a lenguajes como C en seguridad, rendimiento y ergonomía, pero ha tenido dificultades para entrar al mercado comercial. Es interesante ver que JavaScript incorpore esta funcionalidad de INTERCAL. Ojalá esto lleve a un auge de la programación cortés, del mismo modo que los objetos basados en closures de JavaScript llevaron la programación funcional al mainstream

  • Invokers no es algo exclusivo de Chrome. Ya se puede usar también en Firefox Nightly

  • La idea de implementar comportamiento declarativo de UI sin JS es atractiva

    • Elimina el boilerplate de popovers/modales (ya no hace falta manipular aria-expanded)
    • Comandos integrados como show-modal incorporan accesibilidad directamente en el marcado
    • Comandos personalizados (p. ej., --rotate-landscape) permiten que los componentes expongan una API a través de HTML
  • Dudas:

    • Abstracción vs. magia: ¿esto simplemente mueve la complejidad de JS a HTML? Los frameworks ya abstraen el estado. ¿Cómo coexistirá con eso?
    • Fricción con Shadow DOM: hace falta JS para establecer .commandForElement entre distintos shadow roots. Parece un problema resuelto solo a medias
    • Preparación para el futuro: si OpenUI agrega más de 20 comandos (p. ej., show-picker, toggle-details), ¿la plataforma terminará inflándose con sintaxis de nicho?
  • Especificación:

    • elemento button, atributo commandfor
    • elemento button, atributo command
  • ¿Es este el patrón de acciones/mensajería que usaban Next, Be, Apple y otros hace unos 30 años, o se me está escapando algo?

    • Era útil, pero evolucionó hacia un patrón de controlador basado en interfaces debido a la complejidad de mantener el patrón de diseño básico. Así que, si se abre esta caja, espero muchas solicitudes de mejora
  • El toolkit Java de UI temprano de Netscape (IFC) permitía conectar elementos de acción

  • Los nuevos atributos command y commandfor mejoran y reemplazan popovertargetaction y popovertarget

    • ¿Ahora están disponibles de forma predeterminada? ¿Qué significa exactamente que los reemplacen? No pueden simplemente quitarlos algún día porque los desarrolladores web no pueden eliminar con una actualización algo que ya no necesitan
  • Tengo una reacción completamente alérgica a programar con strings. Entiendo las ventajas de accesibilidad, pero no me entusiasma especialmente usar IDs de elementos como otra capa más de comportamiento para apps web

  • No debieron haber implementado esto sin una API completa. En vez de unos 5 comandos, parecería que todas las funciones de JavaScript deberían poder implementarse desde HTML. Eso podría terminar siendo miles de comandos

  • Tenía expectativas de ver command and conquer en HTML

  • Está bien mejorar y ampliar HTML, pero aún falta mucho camino por recorrer. El equipo de HTMX tiene algunas buenas ideas