Tabs

The tabs HTML is based on a w3 example. The JS in the example uses w3's script, but state change implementation will vary by environment.

.c-tabs
<div class="c-tabs">
  <div
    class="c-tabs__list has-text-gray-dark"
    role="tablist"
    aria-label="Seinfeld taglines"
  >
    <button
      class="c-tabs__tab c-tabs__tab--active has-text-teal t-uppercase t-weight-bold t-size-xs t-lsp-m l-pos-rel has-xs-padding"
      role="tab"
      aria-selected="true"
      aria-controls="jerry-tab"
      id="jerry"
    >
      Jerry Seinfeld
    </button>
    <button
      class="c-tabs__tab t-uppercase t-weight-bold t-size-xs t-lsp-m l-pos-rel has-xs-padding"
      role="tab"
      aria-selected="false"
      aria-controls="elaine-tab"
      id="elaine"
      tabindex="-1"
    >
      Elaine Benes
    </button>
    <button
      class="c-tabs__tab t-uppercase t-weight-bold t-size-xs t-lsp-m l-pos-rel has-xs-padding"
      role="tab"
      aria-selected="false"
      aria-controls="cosmo-tab"
      id="cosmo"
      tabindex="-1"
    >
      Cosmo Kramer
    </button>
    <button
      class="c-tabs__tab t-uppercase t-weight-bold t-size-xs t-lsp-m l-pos-rel has-xs-padding"
      role="tab"
      aria-selected="false"
      aria-controls="george-tab"
      id="george"
      tabindex="-1"
    >
      George Costanza
    </button>
  </div>
  <div
    class="has-xs-padding"
    tabindex="0"
    role="tabpanel"
    id="jerry-tab"
    aria-labelledby="jerry"
  >
    <p>Hello, Newman.</p>
    <p>– Jerry</p>
  </div>
  <div
    class="has-xs-padding"
    tabindex="0"
    role="tabpanel"
    id="elaine-tab"
    aria-labelledby="elaine"
    hidden
  >
    <p>Get out!</p>
    <p>– Elaine</p>
  </div>
  <div
    class="has-xs-padding"
    tabindex="0"
    role="tabpanel"
    id="cosmo-tab"
    aria-labelledby="cosmo"
    hidden
  >
    <p>Giddyup!</p>
    <p>– Kramer</p>
  </div>
  <div
    class="has-xs-padding"
    tabindex="0"
    role="tabpanel"
    id="george-tab"
    aria-labelledby="george"
    hidden
  >
    <p>Serenity now.</p>
    <p>– George</p>
  </div>
</div>

<!-- sample JS based on example in w3 -->
<!-- link: https://www.w3.org/TR/wai-aria-practices-1.1/examples/tabs/tabs-1/js/tabs.js -->
<script>
  (function () {
    // implementation approaches may vary, but tabs should always be keyboard accessible
    // and will likely require listeners for left/right keys
    var tabs = document.querySelectorAll('[role="tab"]');
    var panels = document.querySelectorAll('[role="tabpanel"]');
    var activeState = 'c-tabs__tab--active';
    var activeColor = 'has-text-teal';
    var currentIndex = 0;

    function activateTab(tab) {
      // visual style changes
      tab.classList.add(activeState, activeColor);

      // Remove tabindex attribute
      tab.removeAttribute('tabindex');

      // Set the tab as selected
      tab.setAttribute('aria-selected', 'true');

      // Get the value of aria-controls (which is an ID)
      var controls = tab.getAttribute('aria-controls');

      // Remove hidden attribute from tab panel to make it visible
      document.getElementById(controls).removeAttribute('hidden');

      // update current index
      currentIndex = parseInt(tab.dataset.order);

      // update focus
      tab.focus();
    }
    function deactivateTabs() {
      for (var i = 0; i < tabs.length; ++i) {
        tabs[i].classList.remove(activeState, activeColor);
        tabs[i].setAttribute('tabindex', '-1');
        tabs[i].setAttribute('aria-selected', 'false');
      }
      for (var p = 0; p < panels.length; p++) {
        panels[p].setAttribute('hidden', 'hidden');
      }
    }
    function onClick(event) {
      // deactivate all tabs
      deactivateTabs();
      // activate current
      activateTab(event.target);
    }
    function onKeyUp(event) {
      var isOnFirst = currentIndex === 0;
      var isOnLast = currentIndex === tabs.length - 1;
      var noTabActive = currentIndex === -1;
      var isLeftArrow = event.keyCode === 37;
      var isRightArrow = event.keyCode === 39;

      if ((isLeftArrow || isRightArrow) && noTabActive) {
        tabs[0].click();
      } else if (isLeftArrow && isOnFirst) {
        tabs[tabs.length - 1].click();
      } else if (isLeftArrow) {
        tabs[currentIndex - 1].click();
      } else if (isRightArrow && isOnLast) {
        tabs[0].click();
      } else if (isRightArrow) {
        tabs[currentIndex + 1].click();
      }
    }
    for (var i = 0; i < tabs.length; ++i) {
      // assign an index to the tab
      tabs[i].dataset.order = i;
      // click display/hide behavior
      tabs[i].addEventListener('click', onClick);
      // navigate through tabs with left/right keys
      tabs[i].addEventListener('keyup', onKeyUp);
    }
  })();
</script>
RepoCountLocation(s)
texastribune 1