요약
<howto-checkbox>
는 양식의 불리언 옵션을 나타냅니다. 가장 일반적인 체크박스 유형은 사용자가 선택과 선택 해제라는 두 가지 옵션 간에 전환할 수 있는 이중 유형입니다.
요소는 처음 생성될 때 role="checkbox"
및 tabindex="0"
속성을 자체 적용하려고 시도합니다. role
속성은 스크린 리더와 같은 보조 기술이 사용자에게 어떤 종류의 컨트롤인지 알리는 데 도움이 됩니다. tabindex
속성은 요소를 탭 순서에 선택하여 키보드로 포커스를 맞추고 작동할 수 있도록 합니다. 이 두 주제에 관해 자세히 알아보려면 ARIA의 기능 및 tabindex 사용을 참고하세요.
체크박스가 선택되면 checked
불리언 속성이 추가되고 상응하는 checked
속성이 true
로 설정됩니다. 또한 요소는 상태에 따라 aria-checked
속성을 "true"
또는 "false"
로 설정합니다. 마우스나 스페이스바를 사용하여 체크박스를 클릭하면 이러한 선택 상태가 전환됩니다.
체크박스는 disabled
상태도 지원합니다. disabled
속성이 true로 설정되거나 disabled
속성이 적용되면 체크박스가 aria-disabled="true"
를 설정하고 tabindex
속성을 삭제하며 체크박스가 현재 activeElement
인 경우 문서로 포커스를 반환합니다.
체크박스는 액세스 가능한 이름을 갖도록 howto-label
요소와 페어링됩니다.
참조
데모
사용 예
<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>
요소에서 콘텐츠를 클론하는 것이 innerHTML을 사용하는 것보다 성능이 더 좋습니다. 추가 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'];
}
요소의 생성자는 새 인스턴스가 생성될 때마다 실행됩니다. 인스턴스는 HTML을 파싱하거나 document.createElement('howto-checkbox')를 호출하거나 new HowToCheckbox()를 호출하여 만듭니다. 생성자는 shadow DOM을 만드는 데 적합한 위치이지만 속성이나 light DOM 자식은 아직 사용할 수 없으므로 건드리지 않아야 합니다.
constructor() {
super();
this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
connectedCallback()
는 요소가 DOM에 삽입될 때 실행됩니다. 초기 role
, tabindex
, 내부 상태를 설정하고 이벤트 리스너를 설치하기에 적합한 위치입니다.
connectedCallback() {
if (!this.hasAttribute('role'))
this.setAttribute('role', 'checkbox');
if (!this.hasAttribute('tabindex'))
this.setAttribute('tabindex', 0);
프로토타입이 이 클래스에 연결되기 전에 사용자가 요소의 인스턴스에 속성을 설정할 수 있습니다. _upgradeProperty()
메서드는 인스턴스 속성을 확인하고 적절한 클래스 setter를 통해 실행합니다. 자세한 내용은 지연 속성 섹션을 참고하세요.
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);
}
속성과 해당 속성은 서로 미러링되어야 합니다. 선택된 속성 setter는 참/거짓 값을 처리하고 이를 속성 상태에 반영합니다. 자세한 내용은 재진입 방지 섹션을 참고하세요.
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()
는 observedAttributes 배열의 속성이 변경될 때 호출됩니다. 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()
은 확인된 setter를 호출하고 상태를 전환합니다. _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);
})();