Résumé
<howto-checkbox>
représente une option booléenne dans un formulaire. Le type le plus courant
de case à cocher est un double type qui permet à l'utilisateur de basculer entre
(cochés ou non).
L'élément tente d'appliquer lui-même les attributs role="checkbox"
et
tabindex="0"
lors de sa création. L'attribut role
permet
une technologie comme un lecteur d'écran,
indiquer à l'utilisateur de quel type de contrôle il s'agit.
L'attribut tabindex
active l'élément dans l'ordre de tabulation, ce qui en fait un clavier
sélectionnables et maniables. Pour en savoir plus sur ces deux sujets, consultez
Que peut faire ARIA ? et Utilisation de tabindex.
Lorsque la case est cochée, un attribut booléen checked
est ajouté et définit
une propriété checked
correspondante à true
. De plus, l'élément définit une
l'attribut aria-checked
à "true"
ou "false"
, selon ses
de l'état. Si vous cliquez sur la case à cocher avec la souris ou la barre d'espace,
cochés.
La case à cocher accepte également un état disabled
. Si la propriété disabled
est défini sur "true" ou que l'attribut disabled
est appliqué, la case à cocher
aria-disabled="true"
, supprime l'attribut tabindex
et remet le focus.
au document si la case à cocher correspond à la valeur activeElement
actuelle.
La case à cocher est associée à un élément howto-label
pour garantir qu'elle comporte un
nom accessible.
Référence
- Guide d'utilisation: Composants sur GitHub
- Modèle de case à cocher dans les pratiques de création ARIA 1.1
- Que peut faire ARIA ?
- Utiliser l'index de tabulation
Démo
Voir la démonstration en direct sur GitHub
Exemple d'utilisation
<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() {
Définissez des codes de touche pour faciliter la gestion des événements de clavier.
const KEYCODE = {
SPACE: 32,
};
Le clonage du contenu à partir d'un élément <template>
est plus performant que d'utiliser innerHTML, car cela permet d'éviter des coûts d'analyse HTML supplémentaires.
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'];
}
Le constructeur de l'élément est exécuté chaque fois qu'une instance est créée. Les instances sont créées en analysant le code HTML, en appelant document.createElement('howto-checkbox') ou en appelant la méthode new HowToCheckbox(). Le constructeur est idéal pour créer un Shadow DOM, mais vous devez éviter de modifier les attributs ou les enfants Light DOM, car ils ne sont peut-être pas encore disponibles.
constructor() {
super();
this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
connectedCallback()
se déclenche lorsque l'élément est inséré dans le DOM. C'est un bon endroit pour définir les role
et tabindex
initiaux, l'état interne et les écouteurs d'événements d'installation.
connectedCallback() {
if (!this.hasAttribute('role'))
this.setAttribute('role', 'checkbox');
if (!this.hasAttribute('tabindex'))
this.setAttribute('tabindex', 0);
Un utilisateur peut définir une propriété sur une instance d'un élément avant que son prototype ne soit connecté à cette classe. La méthode _upgradeProperty()
vérifie les propriétés de l'instance et les exécute via les setters de classe appropriés. Pour en savoir plus, consultez la section Propriétés différées.
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()
se déclenche lorsque l'élément est supprimé du DOM. C'est un bon endroit pour effectuer des tâches de nettoyage comme la libération des références et la suppression des écouteurs d'événements.
disconnectedCallback() {
this.removeEventListener('keyup', this._onKeyUp);
this.removeEventListener('click', this._onClick);
}
Les propriétés et leurs attributs correspondants doivent se mettre en miroir. Le setter de la propriété pour la case cochée gère les valeurs exactes/falsifiées et reflète celles-ci en fonction de l'état de l'attribut. Pour en savoir plus, consultez la section Éviter l'entraide.
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()
est appelé lorsque l'un des attributs du tableau observeAttributes est modifié. C'est un bon endroit pour gérer les effets secondaires, comme la définition d'attributs 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'attribut tabindex
ne permet pas de supprimer complètement la sélection d'un élément. Vous pouvez toujours sélectionner les éléments comportant tabindex=-1
avec la souris ou en appelant focus()
. Pour vous assurer qu'un élément est désactivé et qu'il n'est pas sélectionnable, supprimez l'attribut tabindex
.
if (hasValue) {
this.removeAttribute('tabindex');
Si cet élément est actuellement sélectionné, annulez-le en appelant la méthode HTMLElement.blur()
.
this.blur();
} else {
this.setAttribute('tabindex', '0');
}
break;
}
}
_onKeyUp(event) {
Ils ne gèrent pas les raccourcis de modificateur généralement utilisés par les technologies d’assistance.
if (event.altKey)
return;
switch (event.keyCode) {
case KEYCODE.SPACE:
event.preventDefault();
this._toggleChecked();
break;
Toute autre pression de touche est ignorée et renvoyée au navigateur.
default:
return;
}
}
_onClick(event) {
this._toggleChecked();
}
_toggleChecked()
appelle le setter coché et inverse son état. Comme _toggleChecked()
n'est causé que par une action de l'utilisateur, il envoie également un événement de modification. Cet événement s'affiche dans des bulles pour imiter le comportement natif de <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);
})();