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) {
   ...