EU System

Tabs

Why and how to use this component

Tabs make it easy to explore and switch between different, often equally important, views or to browse categorized data sets.

When to use this component

  • when there are multiple sets of information that need to be shown in the same area
  • when quick navigation between views is needed, while the rest of the page stays the same
  • use tabs sparingly though. Often in-page navigation can be used instead

Do not use this component

  • in small viewports and some languages long tab labels make very difficult or almost impossible to use tabs
  • if tab labels start getting long, it’s an indication that tabs are probably not the right way to present the content don’t use more than 3 tabs

Resources

<div class="ecl-tabs">
  <ul role="tablist" class="ecl-tabs__tablist ecl-navigation-list ecl-navigation-list--tabs">
    <li role="tab" aria-selected="false" aria-controls="nils-tab" id="nils" tabindex="-1" class="ecl-navigation-list__item ecl-navigation-list__link">Nils Frahm</li>
    <li role="tab" aria-selected="false" aria-controls="helios-tab" id="helios" tabindex="-1" class="ecl-navigation-list__item ecl-navigation-list__link">Helios</li>
    <li role="tab" aria-selected="true" aria-controls="complexcomplex" id="complex" tabindex="0" class="ecl-navigation-list__item ecl-navigation-list__link">Joke</li>
  </ul>

  <section role="tabpanel" id="nils-tab" aria-labelledby="nils" aria-hidden="true" class="ecl-tabs__tabpanel" tabindex="0">
    <p>Nils Frahm is a German musician, composer and record producer based in Berlin. He is known for combining classical and electronic music and for an unconventional approach to the piano in which he mixes a grand piano, upright piano, Roland Juno-60, Rhodes piano, drum machine, and Moog Taurus.</p>
  </section>

  <section role="tabpanel" id="helios-tab" aria-labelledby="helios" aria-hidden="true" class="ecl-tabs__tabpanel" tabindex="0">
    <p>Helios (Keith Kenniff) is an American composer, multi-instrumentalist, and electronic music producer. He composes ambient/electronic music under the moniker Helios and post-classical piano music under Goldmund. He is also one half of the indie band Mint Julep, and ambient project "A Pale Fire". Keith is also a composer for film, television, dance and performance art. In 2010 he created the record label Unseen.</p>
  </section>

  <section role="tabpanel" id="complexcomplex" aria-labelledby="complex" aria-hidden="false" class="ecl-tabs__tabpanel" tabindex="0">
    <p>Fear of complicated buildings:</p>
    <p>A complex complex complex.</p>
  </section>
</div>
{
  "_demo": {
    "scripts": "document.addEventListener('DOMContentLoaded', function () {\n        ECL.tabs();\n      });"
  }
}
<div class="ecl-tabs">
  <ul role="tablist" class="ecl-tabs__tablist ecl-navigation-list ecl-navigation-list--tabs">
    <li role="tab" aria-selected="false" aria-controls="nils-tab" id="nils" tabindex="-1" class="ecl-navigation-list__item ecl-navigation-list__link">Nils Frahm</li>
    <li role="tab" aria-selected="false" aria-controls="helios-tab" id="helios" tabindex="-1" class="ecl-navigation-list__item ecl-navigation-list__link">Helios</li>
    <li role="tab" aria-selected="true" aria-controls="complexcomplex" id="complex" tabindex="0" class="ecl-navigation-list__item ecl-navigation-list__link">Joke</li>
  </ul>

  <section role="tabpanel" id="nils-tab" aria-labelledby="nils" aria-hidden="true" class="ecl-tabs__tabpanel" tabindex="0">
    <p>Nils Frahm is a German musician, composer and record producer based in Berlin. He is known for combining classical and electronic music and for an unconventional approach to the piano in which he mixes a grand piano, upright piano, Roland Juno-60, Rhodes piano, drum machine, and Moog Taurus.</p>
  </section>

  <section role="tabpanel" id="helios-tab" aria-labelledby="helios" aria-hidden="true" class="ecl-tabs__tabpanel" tabindex="0">
    <p>Helios (Keith Kenniff) is an American composer, multi-instrumentalist, and electronic music producer. He composes ambient/electronic music under the moniker Helios and post-classical piano music under Goldmund. He is also one half of the indie band Mint Julep, and ambient project "A Pale Fire". Keith is also a composer for film, television, dance and performance art. In 2010 he created the record label Unseen.</p>
  </section>

  <section role="tabpanel" id="complexcomplex" aria-labelledby="complex" aria-hidden="false" class="ecl-tabs__tabpanel" tabindex="0">
    <p>Fear of complicated buildings:</p>
    <p>A complex complex complex.</p>
  </section>
</div>
  • Content:
    // Heavily inspired by the tab component from https://github.com/frend/frend.co
    
    import { queryAll } from '@ecl/eu-base/helpers/dom';
    
    /**
     * @param {object} options Object containing configuration overrides
     */
    export const tabs = ({
      selector: selector = '.ecl-tabs',
      tablistSelector: tablistSelector = '.ecl-tabs__tablist',
      tabpanelSelector: tabpanelSelector = '.ecl-tabs__tabpanel',
      tabelementsSelector: tabelementsSelector = `${tablistSelector} li`,
    } = {}) => {
      // SUPPORTS
      if (
        !('querySelector' in document) ||
        !('addEventListener' in window) ||
        !document.documentElement.classList
      )
        return null;
    
      // SETUP
      // set tab element NodeList
      const tabContainers = queryAll(selector);
    
      // ACTIONS
      function showTab(target, giveFocus = true) {
        const siblingTabs = queryAll(
          `${tablistSelector} li`,
          target.parentElement.parentElement
        );
        const siblingTabpanels = queryAll(
          tabpanelSelector,
          target.parentElement.parentElement
        );
    
        // set inactives
        siblingTabs.forEach(tab => {
          tab.setAttribute('tabindex', -1);
          tab.removeAttribute('aria-selected');
        });
    
        siblingTabpanels.forEach(tabpanel => {
          tabpanel.setAttribute('aria-hidden', 'true');
        });
    
        // set actives and focus
        target.setAttribute('tabindex', 0);
        target.setAttribute('aria-selected', 'true');
        if (giveFocus) target.focus();
        document
          .getElementById(target.getAttribute('aria-controls'))
          .removeAttribute('aria-hidden');
      }
    
      // EVENTS
      function eventTabClick(e) {
        showTab(e.currentTarget);
        e.preventDefault(); // look into remove id/settimeout/reinstate id as an alternative to preventDefault
      }
    
      function eventTabKeydown(e) {
        // collect tab targets, and their parents' prev/next (or first/last)
        const currentTab = e.currentTarget;
        const previousTabItem =
          currentTab.previousElementSibling ||
          currentTab.parentElement.lastElementChild;
        const nextTabItem =
          currentTab.nextElementSibling ||
          currentTab.parentElement.firstElementChild;
    
        // don't catch key events when ⌘ or Alt modifier is present
        if (e.metaKey || e.altKey) return;
    
        // catch left/right and up/down arrow key events
        // if new next/prev tab available, show it by passing tab anchor to showTab method
        switch (e.keyCode) {
          case 37:
          case 38:
            showTab(previousTabItem);
            e.preventDefault();
            break;
          case 39:
          case 40:
            showTab(nextTabItem);
            e.preventDefault();
            break;
          default:
            break;
        }
      }
    
      // BINDINGS
      function bindTabsEvents(tabContainer) {
        const tabsElements = queryAll(tabelementsSelector, tabContainer);
        // bind all tab click and keydown events
        tabsElements.forEach(tab => {
          tab.addEventListener('click', eventTabClick);
          tab.addEventListener('keydown', eventTabKeydown);
        });
      }
    
      function unbindTabsEvents(tabContainer) {
        const tabsElements = queryAll(tabelementsSelector, tabContainer);
        // unbind all tab click and keydown events
        tabsElements.forEach(tab => {
          tab.removeEventListener('click', eventTabClick);
          tab.removeEventListener('keydown', eventTabKeydown);
        });
      }
    
      // DESTROY
      function destroy() {
        tabContainers.forEach(unbindTabsEvents);
      }
    
      // INIT
      function init() {
        tabContainers.forEach(bindTabsEvents);
      }
    
      // Automatically init
      init();
    
      // REVEAL API
      return {
        init,
        destroy,
      };
    };
    
    // module exports
    export default tabs;
    
  • URL: /components/raw/eu-component-tab/eu-component-tab.js
  • Filesystem Path: ../../src/systems/eu/eu-component/eu-component-tab/eu-component-tab.js
  • Size: 3.6 KB
  • Content:
    /**
     * Tabs
     * @define tabs
     */
    
    // Import base and generic
    @import '@ecl/eu-base/eu-base';
    @import '@ecl/generic-component-tab/generic-component-tab';
    
    // Check if overridden dependencies are already loaded, if needed
    @include check-imports(('eu-component-navigation-list'));
    
    // Use generic mixin
    @include exports('eu-component-tabs') {
      @include ecl-tabs();
    }
    
  • URL: /components/raw/eu-component-tab/eu-component-tab.scss
  • Filesystem Path: ../../src/systems/eu/eu-component/eu-component-tab/eu-component-tab.scss
  • Size: 364 Bytes
  • Handle: @ecl/eu-component-tab
  • Tags: organism
  • Preview:
  • Filesystem Path: ../../src/systems/eu/eu-component/eu-component-tab/eu-component-tab.twig