4 points par GN⁺ 2025-03-08 | 1 commentaires | Partager sur WhatsApp
  • Les boutons sont essentiels pour créer des applications web dynamiques. Ils servent à ouvrir des menus, changer d’action et soumettre des formulaires
  • Dans Chrome 135, les nouveaux attributs command et commandfor améliorent et remplacent les anciens attributs popovertargetaction et popovertarget
  • Problèmes rencontrés jusqu’ici lors de l’implémentation du comportement des boutons :
    • Les gestionnaires HTML onclick peuvent être limités dans le code réel à cause des politiques de sécurité (CSP)
    • Il faut synchroniser l’état entre le bouton et d’autres éléments, et le code de gestion d’état tout en préservant l’accessibilité est complexe
    • Même avec React, AlpineJS, Svelte, etc., la gestion de l’état et des événements reste complexe

Le modèle command et commandfor

  • Les attributs command et commandfor permettent à un bouton d’agir de manière déclarative sur un autre élément. Cela apporte la commodité d’un framework tout en conservant la flexibilité
  • Le bouton commandfor utilise un ID (comme l’attribut for) et command accepte des valeurs intégrées, ce qui offre une approche plus intuitive
  • Exemple : implémentation d’un bouton d’ouverture de menu
    • Pas besoin de aria-expanded ni de JavaScript supplémentaire
    <button commandfor="my-menu" command="show-popover">  
      Open Menu  
    </button>  
    <div popover id="my-menu">  
      <!-- ... -->  
    </div>  
    

command et commandfor vs popovertargetaction et popovertarget

  • Si vous avez déjà utilisé popover, ces attributs popovertarget et popovertargetaction vous sont peut-être familiers
  • Ils fonctionnent de manière similaire à commandfor et command, mais sont spécifiques aux popovers
  • Les nouveaux attributs remplacent complètement les anciens et apportent des fonctionnalités supplémentaires

Commandes intégrées

  • L’attribut command intègre des actions associées à différentes API
    • show-popover : correspond à el.showPopover()
    • hide-popover : correspond à el.hidePopover()
    • toggle-popover : correspond à el.togglePopover()
    • show-modal : correspond à dialogEl.showModal()
    • close : correspond à dialogEl.close()
  • Exemple : implémentation d’une boîte de dialogue de confirmation de suppression
    • Gestion de l’état et de l’accessibilité possible sans 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>  
    
    • Code de traitement du résultat : la valeur de retour peut être traitée dans l’événement close de la boîte de dialogue
    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");  
      }  
    });  
    

Commandes personnalisées

  • En plus des commandes intégrées, il est possible de définir des commandes personnalisées en utilisant le préfixe --
  • Les commandes personnalisées déclenchent un événement "command" sur l’élément cible, mais n’exécutent pas de logique supplémentaire
  • Exemple : implémentation d’une commande de rotation d’image
    <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>  
    

Traitement des commandes dans le Shadow DOM

  • Dans le Shadow DOM, commandfor fonctionne sur la base des ID, ce qui impose les limitations suivantes :
    • Impossible de référencer des éléments entre plusieurs Shadow DOM
    • Dans ce cas, il est possible d’utiliser l’API JavaScript pour définir la propriété .commandForElement
  • Exemple : connexion de commande dans le 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>  
    

Suite du programme

  • Chrome prévoit d’ajouter d’autres commandes intégrées :
    • ouverture et fermeture des éléments <details>
    • prise en charge de la commande show-picker sur <input> et <select>
    • commandes de lecture pour <video> et <audio>
    • fonctionnalité de copie de texte depuis un élément

1 commentaires

 
GN⁺ 2025-03-08
Avis Hacker News
  • Les théoriciens des langages de programmation spéculent depuis les années 80 sur « comefrom », une version plus puissante de « goto ». Cela n’a été implémenté que dans intercal. intercal est supérieur à des langages comme C en matière de sécurité, de performances et d’ergonomie, mais peine à percer sur le marché commercial. Il est intéressant de voir JavaScript intégrer cette fonctionnalité d’intercal. Espérons que cela mène à une explosion de la programmation courtoise, comme les objets à fermeture de JavaScript ont amené la programmation fonctionnelle dans le courant dominant

  • Les invokers ne sont pas propres à Chrome. Ils sont déjà disponibles aussi dans Firefox nightly

  • L’idée d’implémenter des comportements d’UI déclaratifs sans JS est séduisante

    • Cela supprime le boilerplate des popovers/modales (pas besoin de manipuler aria-expanded)
    • Des commandes intégrées comme show-modal intègrent l’accessibilité directement dans le balisage
    • Les commandes personnalisées (p. ex. --rotate-landscape) permettent aux composants d’exposer une API via HTML
  • Questions :

    • Abstraction vs magie : est-ce que cela ne fait que déplacer la complexité du JS vers le HTML ? Les frameworks abstraient déjà l’état. Comment cela va-t-il coexister ?
    • Frictions avec le Shadow DOM : il faut du JS pour définir .commandForElement entre des shadow roots. Cela ressemble à un problème seulement à moitié résolu
    • Pérennité : si OpenUI ajoute plus de 20 commandes (p. ex. show-picker, toggle-details), la plateforme va-t-elle enfler avec une syntaxe de niche ?
  • Spécification :

    • élément button, attribut commandfor
    • élément button, attribut command
  • Est-ce que c’est le pattern action/messagerie qu’utilisaient Next, Be, Apple et d’autres il y a environ 30 ans, ou bien est-ce que quelque chose m’échappe ?

    • C’était utile, mais cela a évolué vers un pattern de contrôleur basé sur des interfaces, à cause de la complexité nécessaire pour préserver des patterns de conception fondamentaux. Donc si cette boîte est ouverte, je m’attends à beaucoup de demandes d’amélioration
  • La première boîte à outils UI Java de Netscape (IFC) permettait de relier des éléments d’action

  • Les nouveaux attributs command et commandfor améliorent et remplacent popovertargetaction et popovertarget

    • Sont-ils désormais disponibles par défaut ? Que signifie exactement « remplacer » ? Les retirer un jour ? Les développeurs web ne peuvent pas supprimer par mise à jour des choses dont ils n’ont plus besoin
  • Je suis complètement allergique au fait de programmer avec des chaînes de caractères. Je comprends les avantages pour l’accessibilité, mais je ne suis pas particulièrement enthousiaste à l’idée d’utiliser des ID d’éléments comme une couche supplémentaire de comportement pour les applications web

  • Cela n’aurait pas dû être implémenté sans l’API complète. Au lieu de 5 commandes environ, on dirait qu’il devrait être possible d’implémenter toutes les fonctionnalités JavaScript via HTML. Cela pourrait représenter des milliers de commandes

  • Je m’attendais à du command and conquer dans HTML

  • C’est bien d’améliorer et d’étendre HTML, mais il reste encore beaucoup de chemin à parcourir. L’équipe HTMX a quelques bonnes idées