ハウツー コンポーネント – ハウツーチェックボックス

まとめ

<howto-checkbox> は、フォーム内のブール値オプションを表します。最も一般的なタイプのチェックボックスはデュアルタイプで、ユーザーはオン / オフの 2 つの選択肢を切り替えることができます。

この要素は、属性 role="checkbox"tabindex="0" が最初に作成されたときに自己適用しようとします。role 属性は、スクリーン リーダーなどの支援技術がどのようなコントロールであるかをユーザーに伝えるのに役立ちます。tabindex 属性は、要素をタブオーダーに設定し、キーボードをフォーカスして操作できるようにします。この 2 つのトピックの詳細については、ARIA でできることtabindex の使用をご覧ください。

このチェックボックスをオンにすると、checked ブール値属性が追加され、対応する checked プロパティが true に設定されます。さらに、この要素では、その状態に応じて aria-checked 属性を "true" または "false" に設定します。マウスまたはスペースバーでチェックボックスをクリックすると、これらのオンの状態が切り替わります。

このチェックボックスは disabled 状態もサポートしています。disabled プロパティが true に設定されているか disabled 属性が適用されている場合、チェックボックスは aria-disabled="true" を設定し、tabindex 属性を削除し、チェックボックスが現在の activeElement であればドキュメントにフォーカスを返します。

チェックボックスを howto-label 要素とペアにして、ユーザー補助機能でアクセス可能な名前を設定します。

リファレンス

デモ

GitHub でライブデモを見る

使用例

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

コード

(function() {

キーボード イベントの処理に役立つキーコードを定義します。

  const KEYCODE = {
    SPACE: 32,
  };

<template> 要素からコンテンツのクローンを作成すると、追加の HTML 解析コストが回避されるため、innerHTML を使用するよりもパフォーマンスが向上します。

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

要素のコンストラクタは、新しいインスタンスが作成されるたびに実行されます。インスタンスを作成するには、HTML を解析するか、document.createElement('howto-checkbox' を呼び出す)、または新しい HowToCheckbox(); を呼び出します。コンストラクタは、Shadow DOM の作成に適した場所ですが、属性や Light DOM の子がまだ利用できない可能性があるため、触れないようにしてください。

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

connectedCallback() は、要素が DOM に挿入されると起動されます。初期の roletabindex、内部状態、インストール イベント リスナーを設定する場所が適しています。

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

プロトタイプがこのクラスに接続される前に、ユーザーは要素のインスタンスにプロパティを設定できます。_upgradeProperty() メソッドはインスタンス プロパティがあるかどうかを確認し、適切なクラスセッターを使って実行します。詳しくは、遅延プロパティのセクションをご覧ください。

      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() は、要素が DOM から削除されると起動されます。この場所は、参照のリリースやイベント リスナーの削除などのクリーンアップ作業を行うのに適しています。

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

プロパティとそれに対応する属性は相互にミラーリングする必要があります。チェック対象のプロパティ セッターは、真実/偽値を処理し、それらを属性の状態に反映します。詳しくは、再アクセスの回避をご覧ください。

    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() は、観測された属性配列内のいずれかの属性が変更されると呼び出されます。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);

tabindex 属性では、要素からフォーカス可能性を完全に削除することはできません。tabindex=-1 が指定された要素には、マウスを使用するか focus() を呼び出して引き続きフォーカスできます。要素を無効にしてフォーカス可能にするには、tabindex 属性を削除します。

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

現在この要素にフォーカスがある場合は、HTMLElement.blur() メソッドを呼び出してフォーカスを解除します。

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

    _onKeyUp(event) {

支援技術で一般的に使用される修飾ショートカットは操作しないでください。

      if (event.altKey)
        return;

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

他のキーを押しても、無視されてブラウザに返されます。

        default:
          return;
      }
    }

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

_toggleChecked() は、チェックされたセッターを呼び出し、その状態を反転します。_toggleChecked() はユーザーの操作によってのみ発生するため、変更イベントもディスパッチします。このイベントは、<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);
})();