Componenti HowTo - casella di controllo istruzioni

Un <howto-checkbox> rappresenta un'opzione booleana in un modulo. Il tipo più comune di casella di controllo è un doppio tipo che consente all'utente di alternare tra due opzioni: selezionata e deselezionata.

L'elemento tenta di applicare automaticamente gli attributi role="checkbox" e tabindex="0" al momento della prima creazione. L'attributo role consente alle tecnologie per la disabilità, come uno screen reader, di comunicare all'utente di che tipo di controllo si tratta. L'attributo tabindex inserisce l'elemento nell'ordine tabulazione, rendendolo attivabile e acquisibile dalla tastiera. Per scoprire di più su questi due argomenti, consulta Che cosa può fare ARIA? e Utilizzare tabindex.

Se la casella di controllo è selezionata, viene aggiunto un attributo booleano checked e viene impostata una proprietà checked corrispondente su true. Inoltre, l'elemento imposta un attributo aria-checked su "true" o "false", a seconda del suo stato. Se fai clic sulla casella di controllo con il mouse o la barra spaziatrice, questi stati controllati vengono attivati e disattivati.

La casella di controllo supporta anche uno stato disabled. Se la proprietà disabled è impostata su true o se viene applicato l'attributo disabled, la casella di controllo imposta aria-disabled="true", rimuove l'attributo tabindex e restituisce il focus al documento se la casella di controllo è l'activeElement corrente.

La casella di controllo è accoppiata a un elemento howto-label per garantire che abbia un nome accessibile.

Riferimento

Demo

Visualizza la demo in tempo reale su GitHub

Esempio di utilizzo

<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>

Codice

(function() {

Definisci i codici tasti per facilitare la gestione degli eventi della tastiera.

  const KEYCODE = {
    SPACE: 32,
  };

La clonazione dei contenuti da un elemento <template> ha prestazioni migliori rispetto all'utilizzo di innerHTML perché evita costi aggiuntivi di analisi HTML.

  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'];
    }

Il costruttore dell'elemento viene eseguito ogni volta che viene creata una nuova istanza. Le istanze vengono create analizzando il codice HTML, chiamando document.createElement('howto-checkbox') o chiamando new HowToCheckbox(); il costruttore è un buon punto di partenza per creare il DOM ombra, anche se dovresti evitare di modificare gli attributi o gli elementi secondari del DOM leggero perché potrebbero non essere ancora disponibili.

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

connectedCallback() viene attivato quando l'elemento viene inserito nel DOM. È un buon punto per impostare lo stato interno iniziale di role, tabindex e installare gli ascoltatori di eventi.

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

Un utente può impostare una proprietà su un'istanza di un elemento prima che il relativo prototipo sia stato collegato a questa classe. Il metodo _upgradeProperty() controllerà eventuali proprietà di istanze ed eseguirle tramite i setter di classe appropriati. Per ulteriori dettagli, consulta la sezione Proprietà lazy.

      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() si attiva quando l'elemento viene rimosso dal DOM. È un buon posto per eseguire operazioni di pulizia come rilasciare riferimenti e rimuovere ascoltatori di eventi.

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

Le proprietà e i relativi attributi corrispondenti devono essere uguali. Il settatore della proprietà per checked gestisce i valori veri/falsi e li riflette nello stato dell'attributo. Per ulteriori dettagli, consulta la sezione Evitare la ricorsione.

    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() viene chiamato quando viene modificato uno degli attributi nell'array observedAttributes. È un ottimo posto per gestire effetti collaterali, come l'impostazione di attributi ARIA.

    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);

L'attributo tabindex non fornisce un modo per rimuovere completamente l'attivabilità da un elemento. Gli elementi con tabindex=-1 possono comunque essere attivati con il mouse o chiamando focus(). Per assicurarti che un elemento sia disattivato e non sia attivabile, rimuovi l'attributo tabindex.

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

Se lo stato attivo è attualmente su questo elemento, annullalo chiamando il metodo HTMLElement.blur()

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

    _onKeyUp(event) {

Non gestire le scorciatoie dei modificatori generalmente utilizzate dalle tecnologie per la disabilità.

      if (event.altKey)
        return;

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

Qualsiasi altra pressione del tasto viene ignorata e passata di nuovo al browser.

        default:
          return;
      }
    }

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

_toggleChecked() chiama il settatore di controllo e ne inverte lo stato. Poiché _toggleChecked() è causato solo da un'azione dell'utente, verrà inviato anche un evento di modifica. Questo evento viene visualizzato per imitare il comportamento nativo di <input type=checkbox>.

    _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);
})();