JSFiddle - React, Tailwind, and code Playground
by Sergey Kulikov
HTML
<template id="component-template">
<style>
:host([focused]) {
outline: solid 1px red;
}
</style>
<label tabindex="0">
<input
type="checkbox"
role="presentation"
tabindex="-1"
style="pointer-events: none;"
>
<slot></slot>
</label>
</template>
<h1>Focus moving from label to checkbox with tabindex -1</h1>
<custom-checkbox tabindex="0">
Label 1
</custom-checkbox>
<custom-checkbox tabindex="0">
Label 2
</custom-checkbox>
<input value="Out of shadow">
JavaScript
class CustomCheckbox extends HTMLElement {
connectedCallback() {
let template = document.getElementById('component-template');
let content = template.content.cloneNode(true);
this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(content);
this.setAttribute('role', 'checkbox');
this.focusElement = this.shadowRoot.querySelector('label');
this.addEventListener('focusin', e => {
console.log('focusin', e.target, e.relatedTarget);
if (e.composedPath()[0] === this) {
this._focus(e);
} else if (e.composedPath().indexOf(this.focusElement) !== -1) {
this._setFocused(true);
}
});
this.addEventListener('focusout', e => {
console.log('focusout', e.target, e.relatedTarget);
this._setFocused(false);
});
this.addEventListener('keydown', e => {
if (!e.defaultPrevented && e.shiftKey && e.keyCode === 9) {
// Flag is checked in _focus event handler.
this._isShiftTabbing = true;
HTMLElement.prototype.focus.apply(this);
this._setFocused(false);
// Event handling in IE is asynchronous and the flag is removed asynchronously as well
setTimeout(() => this._isShiftTabbing = false, 0);
}
});
this._boundKeydownListener = this._bodyKeydownListener.bind(this);
this._boundKeyupListener = this._bodyKeyupListener.bind(this);
document.body.addEventListener('keydown', this._boundKeydownListener, true);
document.body.addEventListener('keyup', this._boundKeyupListener, true);
}
focus() {
this.focusElement.focus();
this._setFocused(true);
}
_focus(e) {
if (this._isShiftTabbing) {
return;
}
this.focusElement.focus();
this._setFocused(true);
}
_setFocused(focused) {
if (focused) {
this.setAttribute('focused', '');
} else {
this.removeAttribute('focused');
}
}
_bodyKeydownListener(e) {
...