Componenti HowTo - casella di controllo istruzioni

Riepilogo

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

Quando viene creato per la prima volta, l'elemento tenta di applicare autonomamente gli attributi role="checkbox" e tabindex="0". L'attributo role aiuta le tecnologie per la disabilità, come uno screen reader, a indicare all'utente il tipo di controllo. L'attributo tabindex attiva l'elemento nell'ordine delle schede, rendendolo attivabile e utilizzabile dalla tastiera. Per ulteriori informazioni su questi due argomenti, consulta Cosa può fare ARIA? e Utilizzare tabindex.

Quando 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, gli stati selezionati vengono attivati.

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

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

Riferimento

Demo

Visualizza la demo dal vivo 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 dei tasti per facilitare la gestione degli eventi della tastiera.

  const KEYCODE = {
    SPACE: 32,
  };

La clonazione dei contenuti di un elemento <template> è più efficiente rispetto all'uso 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 l'HTML, richiamando document.createElement('howto-checkbox') o chiamando il nuovo HowToCheckbox(). Il costruttore è ideale per creare un DOM shadow, anche se è consigliabile evitare di toccare attributi o elementi secondari DOM leggeri perché potrebbero non essere ancora disponibili.

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

connectedCallback() si attiva quando l'elemento viene inserito nel DOM. È ideale per impostare i valori iniziali role e tabindex, lo stato interno e installare i listener 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() verifica la presenza di proprietà dell'istanza e le esegue tramite i setter delle classi appropriati. Per ulteriori dettagli, consulta la sezione relativa alle proprietà lente.

      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 il rilascio dei riferimenti e la rimozione dei listener di eventi.

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

Le proprietà e gli attributi corrispondenti devono essere speculari. L'impostazione delle proprietà per la casella selezionata gestisce i valori veri e propri o falsificati e riflette questi valori nello stato dell'attributo. Per ulteriori dettagli, consulta la sezione Evitare il rientro.

    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 qualsiasi degli attributi nell'array analyzeAttributes. È un buon posto per gestire gli effetti collaterali, come l'impostazione degli 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 offre un modo per rimuovere completamente la messa a fuoco da un elemento. È possibile impostare lo stato attivo sugli elementi con tabindex=-1 comunque con il mouse o richiamando 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, annulla lo stato attivo chiamando il metodo HTMLElement.blur()

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

    _onKeyUp(event) {

Non gestire le scorciatoie di modifica tipicamente utilizzate dalle tecnologie per la disabilità.

      if (event.altKey)
        return;

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

Qualsiasi altra pressione dei tasti viene ignorata e restituita al browser.

        default:
          return;
      }
    }

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

_toggleChecked() chiama il setter selezionato e cambia lo stato. Poiché _toggleChecked() è causato solo da un'azione dell'utente, invierà anche un evento di modifica. Questo evento mostra le bolle per riprodurre 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);
})();