HowTo-Komponenten – HowTo-Kästchen

Zusammenfassung

Ein <howto-checkbox> steht für eine boolesche Option in einem Formular. Der häufigste Typ Das Kontrollkästchen ist ein Dual-Typ, bei dem der Nutzer Auswahl - aktiviert und deaktiviert.

Das Element versucht, die Attribute role="checkbox" und tabindex="0" fest. Das Attribut role hilft bei der wie Screenreader, um Nutzenden mitzuteilen, welche Art von Steuerung das ist. Mit dem Attribut „tabindex“ wird das Element in die TAB-Reihenfolge verschoben, also per Tastatureingabe fokussierbar und bedienbar. Weitere Informationen zu diesen beiden Themen findest du in Was kann ARIA tun? und Tabindex verwenden.

Wenn das Kästchen angeklickt ist, wird das boolesche Attribut checked hinzugefügt und entsprechende checked-Property für true. Außerdem legt das Element ein aria-checked-Attribut entweder auf "true" oder "false" Bundesstaat. Wenn Sie mit der Maus oder Leertaste auf das Kontrollkästchen klicken, werden diese geprüften Status.

Das Kästchen unterstützt auch den Status disabled. Wenn entweder das Attribut disabled auf „true“ gesetzt ist oder das Attribut disabled angewendet wird, legt das Kästchen fest aria-disabled="true", entfernt das Attribut tabindex und kehrt den Fokus zurück zum Dokument hinzufügen, wenn das Kästchen die aktuelle activeElement ist.

Das Kästchen ist mit einem howto-label-Element gekoppelt, damit es ein barrierefreier Name.

Referenz

Demo

Live-Demo auf GitHub ansehen

Nutzungsbeispiel

<style>
  howto-checkbox {
    vertical-align: middle;
  }
  howto-label {
    vertical-align: middle;
    display: inline-block;
    font-weight: bold;
    font-family: sans-serif;
    font-size: 20px;
    margin-left: 8px;
  }
</style>

<howto-checkbox id="join-checkbox"></howto-checkbox>
<howto-label for="join-checkbox">Join Newsletter</howto-label>

Code

(function() {

Definieren Sie Schlüsselcodes, um die Verarbeitung von Tastaturereignissen zu erleichtern.

  const KEYCODE = {
    SPACE: 32,
  };

Das Klonen von Inhalten aus einem <template>-Element ist leistungsfähiger als das Verwenden von innerHTML, da zusätzliche Kosten für die HTML-Analyse vermieden werden.

  const template = document.createElement('template');

  template.innerHTML = `
    <style>
      :host {
        display: inline-block;
        background: url('../images/unchecked-checkbox.svg') no-repeat;
        background-size: contain;
        width: 24px;
        height: 24px;
      }
      :host([hidden]) {
        display: none;
      }
      :host([checked]) {
        background: url('../images/checked-checkbox.svg') no-repeat;
        background-size: contain;
      }
      :host([disabled]) {
        background:
          url('../images/unchecked-checkbox-disabled.svg') no-repeat;
        background-size: contain;
      }
      :host([checked][disabled]) {
        background:
          url('../images/checked-checkbox-disabled.svg') no-repeat;
        background-size: contain;
      }
    </style>
  `;


  class HowToCheckbox extends HTMLElement {
    static get observedAttributes() {
      return ['checked', 'disabled'];
    }

Der Konstruktor des Elements wird jedes Mal ausgeführt, wenn eine neue Instanz erstellt wird. Instanzen werden entweder durch Parsen von HTML, durch Aufrufen von document.createElement('howto-checkbox') oder durch Aufrufen von new HowToCheckbox() erstellt. Der Konstruktor eignet sich gut zum Erstellen eines Shadow DOM. Sie sollten jedoch keine Attribute oder Light-DOM-Unterelemente berühren, da diese möglicherweise noch nicht verfügbar sind.

    constructor() {
      super();
      this.attachShadow({mode: 'open'});
      this.shadowRoot.appendChild(template.content.cloneNode(true));
    }

connectedCallback() wird ausgelöst, wenn das Element in das DOM eingefügt wird. Hier können Sie die anfänglichen role-, tabindex- und internen Status-Listener sowie Installationsereignis-Listener festlegen.

    connectedCallback() {
      if (!this.hasAttribute('role'))
        this.setAttribute('role', 'checkbox');
      if (!this.hasAttribute('tabindex'))
        this.setAttribute('tabindex', 0);

Ein Nutzer kann eine Eigenschaft für eine Instanz eines Elements festlegen, bevor sein Prototyp mit dieser Klasse verbunden wurde. Die Methode _upgradeProperty() sucht nach Instanzattributen und führt sie durch die richtigen Klassen-Setter. Weitere Informationen finden Sie im Abschnitt Verzögerte Eigenschaften.

      this._upgradeProperty('checked');
      this._upgradeProperty('disabled');

      this.addEventListener('keyup', this._onKeyUp);
      this.addEventListener('click', this._onClick);
    }

    _upgradeProperty(prop) {
      if (this.hasOwnProperty(prop)) {
        let value = this[prop];
        delete this[prop];
        this[prop] = value;
      }
    }

disconnectedCallback() wird ausgelöst, wenn das Element aus dem DOM entfernt wird. Hier können Sie Bereinigungsarbeiten ausführen, z. B. Referenzen veröffentlichen und Ereignis-Listener entfernen.

    disconnectedCallback() {
      this.removeEventListener('keyup', this._onKeyUp);
      this.removeEventListener('click', this._onClick);
    }

Eigenschaften und ihre entsprechenden Attribute sollten sich widerspiegeln. Der Property-Setter für aktivierte Werte verarbeitet wahrheitsgemäße/falsche Werte und spiegelt sie im Status des Attributs wider. Weitere Informationen finden Sie im Abschnitt Widerruf vermeiden.

    set checked(value) {
      const isChecked = Boolean(value);
      if (isChecked)
        this.setAttribute('checked', '');
      else
        this.removeAttribute('checked');
    }

    get checked() {
      return this.hasAttribute('checked');
    }

    set disabled(value) {
      const isDisabled = Boolean(value);
      if (isDisabled)
        this.setAttribute('disabled', '');
      else
        this.removeAttribute('disabled');
    }

    get disabled() {
      return this.hasAttribute('disabled');
    }

attributeChangedCallback() wird aufgerufen, wenn sich eines der Attribute im Array „Beobachtende Attribute“ ändert. Hier können Sie auf Nebenwirkungen wie das Festlegen von ARIA-Attributen reagieren.

    attributeChangedCallback(name, oldValue, newValue) {
      const hasValue = newValue !== null;
      switch (name) {
        case 'checked':
          this.setAttribute('aria-checked', hasValue);
          break;
        case 'disabled':
          this.setAttribute('aria-disabled', hasValue);

Das Attribut tabindex bietet keine Möglichkeit, die Fokussierbarkeit eines Elements vollständig zu entfernen. Elemente mit tabindex=-1 können weiterhin mit einer Maus oder durch Aufrufen von focus() fokussiert werden. Entfernen Sie das Attribut tabindex, damit ein Element deaktiviert und nicht fokussierbar ist.

          if (hasValue) {
            this.removeAttribute('tabindex');

Wenn der Fokus derzeit auf diesem Element liegt, heben Sie den Fokus auf, indem Sie die Methode HTMLElement.blur() aufrufen

            this.blur();
          } else {
            this.setAttribute('tabindex', '0');
          }
          break;
      }
    }

    _onKeyUp(event) {

Verwenden Sie keine Modifikatortasten, die normalerweise von Hilfstechnologien verwendet werden.

      if (event.altKey)
        return;

      switch (event.keyCode) {
        case KEYCODE.SPACE:
          event.preventDefault();
          this._toggleChecked();
          break;

Jeder andere Tastendruck wird ignoriert und an den Browser zurückgegeben.

        default:
          return;
      }
    }

    _onClick(event) {
      this._toggleChecked();
    }

_toggleChecked() ruft den aktivierten Setter auf und dreht seinen Status. Da _toggleChecked() nur durch eine Nutzeraktion verursacht wird, wird auch ein Änderungsereignis ausgelöst. Dieses Ereignis wird erstellt, um das native Verhalten von <input type=checkbox> nachzuahmen.

    _toggleChecked() {
      if (this.disabled)
        return;
      this.checked = !this.checked;
      this.dispatchEvent(new CustomEvent('change', {
        detail: {
          checked: this.checked,
        },
        bubbles: true,
      }));
    }
  }

  customElements.define('howto-checkbox', HowToCheckbox);
})();