4 Punkte von GN⁺ 2025-03-08 | 1 Kommentare | Auf WhatsApp teilen
  • Buttons sind essenziell für die Erstellung dynamischer Webanwendungen. Sie werden verwendet, um Menüs zu öffnen, Aktionen umzuschalten und Formulare abzusenden
  • In Chrome 135 werden mit den neuen Attributen command und commandfor die bisherigen Attribute popovertargetaction und popovertarget verbessert und ersetzt
  • Probleme, die bisher bei der Implementierung von Button-Verhalten auftraten:
    • onclick-Handler in HTML können durch Sicherheitsrichtlinien (CSP) im produktiven Code nur eingeschränkt nutzbar sein
    • Der Status von Buttons und anderen Elementen muss synchronisiert werden, und Code zur Statusverwaltung bei gleichzeitiger Wahrung der Barrierefreiheit ist komplex
    • Auch in React, AlpineJS, Svelte usw. ist das Handling von Status und Events komplex

Das Muster mit command und commandfor

  • Mit den Attributen command und commandfor können Buttons deklarativ auf andere Elemente wirken. Das bietet den Komfort von Frameworks und bleibt zugleich flexibel
  • Ein commandfor-Button verwendet eine ID (ähnlich dem Attribut for), und command akzeptiert eingebaute Werte für einen intuitiveren Ansatz
  • Beispiel: Implementierung eines Buttons zum Öffnen eines Menüs
    • Kein aria-expanded oder zusätzliches JavaScript erforderlich
    <button commandfor="my-menu" command="show-popover">  
      Open Menu  
    </button>  
    <div popover id="my-menu">  
      <!-- ... -->  
    </div>  
    

command und commandfor vs. popovertargetaction und popovertarget

  • Wenn du popover bereits verwendet hast, kennst du vielleicht die Attribute popovertarget und popovertargetaction
  • Diese funktionieren ähnlich wie commandfor und command, sind aber auf Popovers spezialisiert
  • Die neuen Attribute ersetzen die bisherigen vollständig und bieten zusätzliche Funktionen

Eingebaute Befehle

  • Das Attribut command enthält eingebaute Aktionen, die verschiedenen APIs zugeordnet werden
    • show-popover: wird auf el.showPopover() abgebildet
    • hide-popover: wird auf el.hidePopover() abgebildet
    • toggle-popover: wird auf el.togglePopover() abgebildet
    • show-modal: wird auf dialogEl.showModal() abgebildet
    • close: wird auf dialogEl.close() abgebildet
  • Beispiel: Implementierung eines Bestätigungsdialogs zum Löschen
    • Status- und Barrierefreiheitsverwaltung sind ohne JavaScript möglich
    <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 zur Verarbeitung des Ergebnisses: Im close-Event des Dialogs kann der Rückgabewert verarbeitet werden
    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");  
      }  
    });  
    

Benutzerdefinierte Befehle

  • Neben den eingebauten Befehlen können mit dem Präfix -- auch benutzerdefinierte Befehle definiert werden
  • Benutzerdefinierte Befehle lösen auf dem Zielelement das Event "command" aus, führen aber keine zusätzliche Logik aus
  • Beispiel: Implementierung eines Befehls zum Drehen eines Bildes
    <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>  
    

Befehlsverarbeitung im Shadow DOM

  • Im Shadow DOM gibt es bei commandfor, da es auf IDs basiert, folgende Einschränkungen:
    • Elementreferenzen zwischen Shadow-DOMs sind nicht möglich
    • In diesem Fall kann über die JavaScript-API die Eigenschaft .commandForElement gesetzt werden
  • Beispiel: Verknüpfen eines Befehls im 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>  
    

Zukünftige Pläne

  • Chrome plant die Einführung weiterer eingebauter Befehle:
    • Öffnen und Schließen von <details>-Elementen
    • Unterstützung des Befehls show-picker für <input> und <select>
    • Wiedergabebefehle für <video> und <audio>
    • Funktion zum Kopieren von Text aus Elementen

1 Kommentare

 
GN⁺ 2025-03-08
Hacker-News-Kommentare
  • Programmiersprachentheoretiker spekulieren seit den 80ern über "comefrom", eine mächtigere Version von "goto". Implementiert wurde das nur in intercal. intercal ist in Sicherheit, Performance und Ergonomie Sprachen wie C überlegen, hat aber Schwierigkeiten, in den kommerziellen Markt vorzudringen. Es ist interessant zu sehen, wie JavaScript dieses Feature von intercal übernimmt. Hoffentlich führt das zu einem Aufschwung des höflichen Programmierens, so wie die auf Closures basierenden Objekte von JavaScript funktionale Programmierung in den Mainstream gebracht haben

  • Invokers sind nicht nur eine Chrome-Sache. In Firefox Nightly sind sie ebenfalls bereits verfügbar

  • Die Idee, deklaratives UI-Verhalten ohne JS zu implementieren, ist attraktiv

    • Sie entfernt Boilerplate für Popover/Modals (Manipulation von aria-expanded ist nicht nötig)
    • Eingebaute Befehle wie show-modal integrieren Accessibility direkt ins Markup
    • Benutzerdefinierte Befehle (z. B. --rotate-landscape) ermöglichen es Komponenten, ihre API über HTML bereitzustellen
  • Fragen:

    • Abstraktion vs. Magie: Verschiebt das einfach nur Komplexität von JS nach HTML? Frameworks abstrahieren bereits Status. Wie wird das koexistieren?
    • Shadow-DOM-Reibung: Um .commandForElement über Shadow Roots hinweg zu setzen, ist JS nötig. Das wirkt wie ein nur halb gelöstes Problem
    • Zukunftssicherheit: Wenn OpenUI mehr als 20 Befehle hinzufügt (z. B. show-picker, toggle-details), bläht sich die Plattform dann mit Nischen-Syntax auf?
  • Spezifikation:

    • button-Element, commandfor-Attribut
    • button-Element, command-Attribut
  • Ist das das Action-/Messaging-Pattern, das NeXT, Be, Apple usw. vor etwa 30 Jahren verwendet haben, oder übersehe ich etwas?

    • Es war nützlich, entwickelte sich aber wegen der Komplexität, die nötig war, um grundlegende Designmuster beizubehalten, zu interface-basierten Controller-Patterns weiter. Wenn diese Büchse geöffnet wird, sind daher viele Verbesserungswünsche zu erwarten
  • Netscapes frühes Java-UI-Toolkit (IFC) ermöglichte es, Action-Elemente zu verdrahten

  • Die neuen Attribute command und commandfor verbessern und ersetzen popovertargetaction und popovertarget

    • Sind diese jetzt standardmäßig verfügbar? Was bedeutet es, dass sie etwas ersetzen? Werden sie irgendwann entfernt? Webentwickler können Dinge, die nicht mehr nötig sind, nicht einfach per Update entfernen
  • Ich habe eine regelrechte Allergie gegen Programmierung mit Strings. Ich verstehe die Accessibility-Vorteile, bin aber nicht besonders begeistert davon, Element-IDs als weitere Verhaltensschicht für Web-Apps zu verwenden

  • Das hätte nicht ohne die vollständige API implementiert werden sollen. Statt etwa fünf Befehlen wirkt es so, als könnte man über HTML die gesamte JavaScript-Funktionalität abbilden. Das wären Tausende von Befehlen

  • Ich hatte in HTML eher auf "command and conquer" gehofft

  • Es ist gut, HTML zu verbessern und zu erweitern, aber es ist noch ein weiter Weg. Das HTMX-Team hat einige gute Ideen