Hallo <selectmenu>, ein vollständig gestaltbares  select Element

Avatar of Patrick Brosset
Patrick Brosset am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Ich möchte Ihnen ein neues, experimentelles Formularsteuerelement namens <selectmenu> vorstellen. Wir werden uns damit eingehend beschäftigen, einschließlich dessen, wie viel einfacher es zu gestalten ist als ein herkömmliches <select>-Element. Aber zunächst füllen wir etwas Kontext auf, warum überhaupt etwas wie <selectmenu> benötigt wird, da es sich noch weiterentwickelt und in der Entwicklung ist.

Fragen Sie jeden Webentwickler, was seiner Meinung nach heute auf der Webplattform fehlt, und die Möglichkeit, Formularsteuerelemente zu gestalten, wird wahrscheinlich auf seiner Liste stehen. Tatsächlich wurde die Gestaltung von Formularen als eine der Top-10 fehlenden Dinge in der State of CSS Survey im Jahr 2020 gewählt. Anschließend wurde sie von Greg Whitworth weiter untersucht, der zeigte, dass <select> das Steuerelement war, mit dem Webentwickler die meisten Probleme bei der Gestaltung mit CSS hatten.

Während es relativ einfach ist, das Erscheinungsbild des Schaltflächenteils eines <select> zu gestalten (das, was Sie auf der Seite sehen, wenn das Popup geschlossen ist), ist es fast unmöglich, die Optionen zu gestalten (das, was Sie sehen, wenn das Popup geöffnet ist), geschweige denn, mehr Inhalte im Popup hinzuzufügen.

Showing the default UI of the select element in Safari.
Die Standard-Benutzeroberfläche für ein <select> Element in Safari

Infolgedessen haben Designsysteme und Komponentenbibliotheken ihre eigenen Selects entwickelt, die von Grund auf mit benutzerdefiniertem HTML-Markup, CSS und oft viel JavaScript erstellt wurden, um etwas zu haben, das sich gut in andere Komponenten integriert.

Leider ist dies nicht einfach korrekt mit den richtigen semantischen Barrierefreiheitsmerkmalen, Tastaturunterstützung und Popup-Positionierung zu tun. Webentwickler haben über die Jahre hinweg Stunden und Stunden investiert, um immer wieder dieselben Probleme zu lösen, und es gibt viele unzugängliche Selects da draußen.

Es ist an der Zeit, dass wir ein richtig gestaltbares integriertes <select> bekommen, damit wir diesen Code nie wieder schreiben müssen!

Die Open UI Initiative

The Open UI logo, which is a green oval with a rounded fork-like shape with three prongs inside.

Open UI ist eine Gruppe von Entwicklern, Designern und Browser-Implementierern, die sich zum Ziel gesetzt haben, genau dieses Problem zu lösen, und während sie dabei sind, auch andere fehlende Steuerelemente anzugehen.

Ziel von Open UI ist es, Webentwicklern langfristig die Möglichkeit zu geben, integrierte UI-Steuerelemente zu gestalten und zu erweitern (dazu gehören <select>, aber auch Dropdowns, Checkboxen, Radio-Buttons und andere). Um dies zu erreichen, erstellen sie Spezifikationen dafür, wie diese Steuerelemente in der Webplattform implementiert werden sollen, sowie die Barrierefreiheitsanforderungen, die sie erfüllen müssen.

Das Projekt steckt noch in den Kinderschuhen, aber die Dinge bewegen sich schnell und, wie wir unten sehen werden, geschieht bereits Aufregendes.

Sie können der Gruppe beitreten und an den Meetings, Forschungs- und Spezifikationsbemühungen teilnehmen.

Das <selectmenu>-Steuerelement

Basierend auf dem Open UI's <select> Vorschlag wurde die Implementierung eines neuen <selectmenu> Steuerelements in Chromium gestartet! Die Arbeit wird vom Microsoft Edge-Team in Zusammenarbeit mit dem Google Chrome-Team geleistet. Sie ist sogar bereits in Chromium-basierten Browsern verfügbar, indem Sie das Flag "Experimentelle Webplattform-Features" auf der Seite about:flags aktivieren.

<selectmenu> ist ein neues integriertes Steuerelement, das eine Auswahlmöglichkeit bietet, genau wie <select>, mit einer Schaltfläche, die das Label des ausgewählten Werts anzeigt, einem Popup, das erscheint, wenn diese Schaltfläche geklickt wird, und einer Liste von Optionen, die angezeigt werden.

Warum ein neuer Name?

Warum nicht einfach das bestehende <select>-Steuerelement ersetzen? Der Name "selectmenu" begann als Arbeitstitel, scheint sich aber bisher gehalten zu haben, und niemand hat bisher etwas Besseres gefunden.

Wichtiger noch, das bestehende <select>-Steuerelement wird schon sehr lange im Web verwendet. Daher kann es wahrscheinlich niemals in wesentlicher Weise geändert werden, ohne größere Kompatibilitätsprobleme zu verursachen.

Der Plan ist also (und denken Sie daran, das ist alles noch sehr experimentell), dass <selectmenu> ein neues Steuerelement sein wird, unabhängig von <select>.

Probieren Sie es noch heute aus

Dies ist noch nicht für den produktiven Einsatz bereit, aber wenn Sie genauso begeistert davon sind wie ich, hier ist, wie:

  1. Öffnen Sie eine Canary-Version eines Chromium-basierten Browsers (Chrome, Edge).
  2. Schalten Sie das Flag "Experimentelle Webplattform-Features" auf der Seite about:flags um und starten Sie neu.
  3. Ersetzen Sie jedes <select> durch <selectmenu> auf einer Webseite!

Das war's! Es wird standardmäßig nicht viel tun, aber wie wir später sehen werden, können Sie das Steuerelement mit dieser einen Tag-Namensänderung ziemlich umfassend gestalten und erweitern.

Wir freuen uns über Feedback!

Bevor wir darauf eingehen, wie das Steuerelement verwendet wird, wenn Sie es verwenden, würden sich die Open UI-Gruppe und die Leute, die an der Implementierung in Chromium arbeiten, über Ihr Feedback freuen, wenn Sie eines haben.

Als früher Tester können Sie ihnen aktiv helfen, das Steuerelement für alle besser zu machen. Wenn Sie also auf Fehler oder Einschränkungen beim Design des Steuerelements stoßen, senden Sie bitte Ihr Feedback, indem Sie ein Problem im Open UI GitHub-Repository erstellen!

Und nun wollen wir darüber sprechen, wie das Steuerelement funktioniert.

Die Anatomie eines <selectmenu>-Steuerelements

Da die verschiedenen Teile des Selectmenüs gestaltet werden können, ist es wichtig, zuerst seine innere Anatomie zu verstehen.

Showing the boundaries of a selectmenu element.
  • <selectmenu> ist das Wurzelelement, das die Schaltfläche und die Listbox enthält.
  • <button> ist das Element, das die Sichtbarkeit der Listbox auslöst.
  • <selected-value> ist das Element, das den Wert der aktuell ausgewählten Option anzeigt (optional). Beachten Sie, dass dieser Teil nicht unbedingt innerhalb des <button>-Teils platziert werden muss.
  • <listbox> ist der Wrapper, der die <option>s und <optgroup>s enthält.
  • <optgroup> gruppiert Optionen zusammen mit einer optionalen Beschriftung.
  • <option> repräsentiert den potenziellen Wert, der vom Benutzer ausgewählt werden kann. Es kann eine oder mehrere davon geben.

Standardverhalten

Das Standardverhalten des <selectmenu>-Steuerelements imitiert das Verhalten des <select>-Steuerelements. Sie können es wie ein natives <select> verwenden, mit folgendem minimalen Markup.

<selectmenu>
  <option>Option 1</option>
  <option>Option 2</option>
  <option>Option 3</option>
</selectmenu>

Dabei werden die standardmäßigen <button>, <selected-value> und <listbox > für Sie erstellt.

Teile des Steuerelements gestalten

Hier wird es interessant! Eine Möglichkeit, das Steuerelement anz Ihre Anforderungen anzupassen, ist die Verwendung des CSS ::part() Pseudo-Elements, um die verschiedenen Teile innerhalb der Anatomie des Steuerelements auszuwählen, die Sie gestalten möchten.

Betrachten Sie das folgende Beispiel, bei dem ::part() verwendet wird, um die Schaltflächen- und Listbox-Teile zu gestalten

<style>
  .my-select-menu::part(button) {
    color: white;
    background-color: #f00;
    padding: 5px;
    border-radius: 5px;
  }

  .my-select-menu::part(listbox) {
    padding: 10px;
    margin-top: 5px;
    border: 1px solid red;
    border-radius: 5px;
  }
</style>
<selectmenu class="my-select-menu">
  <option>Option 1</option>
  <option>Option 2</option>
  <option>Option 3</option>
</selectmenu>

Das obige Beispiel ergibt die folgende Formatierung

A styled selectmenu element with a red button background and a red border around the listbox.

::part() kann verwendet werden, um die Teile <button>, <selected-value> und <listbox> des Steuerelements zu gestalten.

Verwenden Sie Ihr eigenes Markup

Wenn das Obige nicht ausreicht, können Sie das Steuerelement noch weiter anpassen, indem Sie Ihr eigenes Markup bereitstellen, um das Standard-Markup zu ersetzen, und die Teile erweitern oder neu anordnen.

Ein <selectmenu> hat benannte Slots, auf die Sie verweisen können, um die Standardteile zu ersetzen. Um beispielsweise die Standard-Schaltfläche durch Ihre eigene zu ersetzen, können Sie Folgendes tun:

<style>
  .my-custom-select [slot='button'] {
    display: flex;
    align-content: center;
  }
  .my-custom-select button {
    padding: 5px;
    border: none;
    background: #f06;
    border-radius: 5px 0 0 5px;
    color: white;
    font-weight: bold;
  }
  .my-custom-select .label {
    padding: 5px;
    border: 1px solid #f06;
    border-radius: 0 5px 5px 0;
  }
</style>
<selectmenu class="my-custom-select">
  <div slot="button">
    <button behavior="button">Open</button>
    <span class="label">Choose an option</span>
  </div>
  <option>Option 1</option>
  <option>Option 2</option>
  <option>Option 3</option>
</selectmenu>

Das Attribut slot="button" auf dem äußeren <div> weist das <selectmenu> an, seine Standard-Schaltfläche durch den Inhalt des <div> zu ersetzen.

Das Attribut behavior="button" auf der inneren <button> weist den Browser an, dass dieses Element als neue Schaltfläche verwendet werden soll. Der Browser wendet automatisch das gesamte Klick- und Tastaturverhalten auf dieses Element sowie die entsprechenden semantischen Barrierefreiheitsmerkmale an.

Der obige Codeausschnitt ergibt die folgende Formatierung

A styled selectmenu with a bright pink open button and a box-shadow around the listbox.

Beachten Sie, dass die Attribute slot und behavior auch auf demselben Element verwendet werden können.

Sie können den standardmäßigen Listbox-Teil auf ähnliche Weise ersetzen

<style>
  .my-custom-select [popup] {
    width: 300px;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(100px, 1fr));
    gap: 10px;
    padding: 10px;
    box-shadow: none;
    margin: 10px 0;
    border: 1px solid;
    background: #f7f7f7;
  }
</style>
<selectmenu class="my-custom-select">
  <div slot="listbox">
    <div popup behavior="listbox">
      <option>Option 1</option>
      <option>Option 2</option>
      <option>Option 3</option>
      <option>Option 4</option>
      <option>Option 5</option>
    </div>
  </div>
</selectmenu>

Interessanterweise wird die hier verwendete <div popup> auch von Open UI vorgeschlagen und derzeit in Chromium implementiert.

Das Element mit behavior="listbox" muss ein <div popup> sein. Das Anwenden von behavior="listbox" weist den Browser an, dieses Element zu öffnen, wenn die <selectmenu>-Schaltfläche geklickt wird, und der Benutzer kann <option>s darin mit der Maus, den Pfeiltasten und der Berührung auswählen.

Der obige Codeausschnitt ergibt die folgende Formatierung

A styled selectmenu where the list box is split into two columns.

Erweiterung des Markups

Sie können nicht nur die Standardteile durch Ihre eigenen ersetzen, wie oben gezeigt, sondern auch das Markup des Steuerelements erweitern, indem Sie neue Elemente hinzufügen. Dies kann nützlich sein, um die Listbox oder Schaltfläche mit zusätzlichen Informationen zu ergänzen oder neue Funktionalität hinzuzufügen.

Betrachten Sie das folgende Beispiel

<style>
  .my-custom-select [slot='button'] {
    display: flex;
    align-items: center;
    gap: 1rem;
  }
  .my-custom-select button {
    border: none;
    margin: 0;
    padding: 0;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    display: grid;
    place-content: center;
  }
  .my-custom-select button::before {
    content: '\25BC';
  }
  .my-custom-select [popup] {
    padding: 0;
  }
  .my-custom-select .section {
    padding: 1rem 0 0;
    background: radial-gradient(ellipse 60% 50px at center top, #000a 0%, transparent 130%);
  }
  .my-custom-select h3 {
    margin: 0 0 1rem 0;
    text-align: center;
    color: white;
  }
  .my-custom-select option {
    text-align: center;
    padding: 0.5rem;
  }
</style>
<selectmenu class="my-custom-select">
  <div slot="button">
    <span class="label">Choose a plant</span>
    <span behavior="selected-value" slot="selected-value"></span>
    <button behavior="button"></button>
  </div>
  <div slot="listbox">
    <div popup behavior="listbox">
      <div class="section">
        <h3>Flowers</h3>
        <option>Rose</option>
        <option>Lily</option>
        <option>Orchid</option>
        <option>Tulip</option>
      </div>
      <div class="section">
        <h3>Trees</h3>
        <option>Weeping willow</option>
        <option>Dragon tree</option>
        <option>Giant sequoia</option>
      </div>
    </div>
  </div>
</selectmenu>

Hier verwenden wir benutzerdefiniertes Markup, um die Optionsliste zu umschließen und unseren eigenen Inhalt zu erstellen, wie unten gezeigt

A styled selectmenu that contains options containing sub-options in the listbox.

Ersetzen des gesamten Shadow DOM

Schließlich, und wenn das Obige nicht ausreichte, können Sie das Markup des Steuerelements auch erweitern, indem Sie seinen Standard-Shadow-DOM komplett ersetzen, indem Sie attachShadow() aufrufen. Zum Beispiel könnte die Demo im vorherigen Abschnitt wie folgt modifiziert werden:

<selectmenu id="my-custom-select"></selectmenu>
<script>
  const myCustomSelect = document.querySelector('#my-custom-select')
  const shadow = myCustomSelect.attachShadow({ mode: 'closed' })
  shadow.innerHTML = `
    <style>
    .button-container {
      display: flex;
      align-items: center;
      gap: 1rem;
    }
    button {
      border: none;
      margin: 0;
      padding: 0;
      width: 2rem;
      height: 2rem;
      border-radius: 50%;
      display: grid;
      place-content: center;
    }
    button::before {
      content: '\\0025BC';
    }
    [popup] {
      padding: 0;
    }
    .section {
      padding: 1rem 0 0;
      background: radial-gradient(ellipse 60% 50px at center top, #000a 0%, transparent 130%);
    }
    h3 {
      margin: 0 0 1rem 0;
      text-align: center;
      color: white;
    }
    option {
      text-align: center;
      padding: 0.5rem;
    }
    option:hover {
      background-color: lightgrey;
    }
  </style>
  <div class="button-container">
    <span class="label">Choose a plant</span>
    <span behavior="selected-value" slot="selected-value"></span>
    <button behavior="button"></button>
  </div>
  <div popup behavior="listbox">
    <div class="section">
      <h3>Flowers</h3>
      <option>Rose</option>
      <option>Lily</option>
      <option>Orchid</option>
      <option>Tulip</option>
    </div>
    <div class="section">
      <h3>Trees</h3>
      <option>Weeping willow</option>
      <option>Dragon tree</option>
      <option>Giant sequoia</option>
    </div>
  </div>
  `
</script>

Auf diese Weise ist das benutzerdefinierte Markup des <selectmenu> vollständig in seinem Shadow DOM gekapselt. Das <selectmenu> kann daher in jede Seite eingefügt werden, ohne dass die Stile des umgebenden Inhalts stören.

Schlussbemerkungen

Wie wir gesehen haben, bietet das neue experimentelle <selectmenu>-Steuerelement viel Flexibilität, wenn es um die Gestaltung und sogar die Erweiterung eines traditionellen <select> geht. Und das tut es auf die richtige Weise, denn es ist in den Browser integriert, wo Barrierefreiheit und eine viewport-bewusste Positionierung für Sie gehandhabt werden.

Open UI hat weitere Dokumentation über <selectmenu>, und wenn Sie mehr Code sehen möchten, der zeigt, wie man das <selectmenu> verwendet, hier sind ein paar Demos.

Auch hier handelt es sich um ein sich in Arbeit befindliches Projekt, das sich aufgrund des Feedbacks der Open UI-Gruppe mit ziemlicher Sicherheit ändern wird.

Ich kann es kaum erwarten, dass Spezifikationen in HTML- und CSS-Standardisierungsgremien erscheinen und die Implementierung stabiler wird, und auch, dass andere Browser-Engines daran interessiert werden. Sie können dazu beitragen, dass dies geschieht! Das Testen des Steuerelements, das Melden von Problemen oder das Mitmachen sind alles großartige Möglichkeiten, diese Bemühungen voranzutreiben.