Aria Tablist On GitHub Dependency-free plain JavaScript module for WCAG compliant tablists.
Also great for accordions.

Examples

1. Horizontal tabs (standard example)

Apple
Orange
Pear
An apple is a sweet, edible fruit produced by an apple tree (Malus domestica). Apple trees are cultivated worldwide and are the most widely grown species in the genus Malus. The tree originated in Central Asia, where its wild ancestor, Malus sieversii, is still found today. Apples have been grown for thousands of years in Asia and Europe and were brought to North America by European colonists. Apples have religious and mythological significance in many cultures, including Norse, Greek and European Christian tradition.
The orange is the fruit of the citrus species Citrus × sinensis in the family Rutaceae, native to China. It is also called sweet orange, to distinguish it from the related Citrus × aurantium, referred to as bitter orange. The sweet orange reproduces asexually (apomixis through nucellar embryony); varieties of sweet orange arise through mutations.
The pear (/ˈpɛər/) tree and shrub are a species of genus Pyrus /ˈpaɪrəs/, in the family Rosaceae, bearing the pomaceous fruit of the same name. Several species of pear are valued for their edible fruit and juices while others are cultivated as trees.
<div id="fruits">
    <div aria-controls="apple">Apple</div>
    <div aria-controls="orange">Orange</div>
    <div aria-controls="pear">Pear</div>
<div>

<div id="apple">...</div>
<div id="orange">...</div>
<div id="pear">...</div>

<script>
    AriaTablist(document.getElementById('fruits'));
</script>

As per the WCAG spec, by default, only the active tab is in the page's normal tabbing order; keyboard-only users can navigate to the others using the arrow keys, or you can set the focusableTabs option to true (in the next example) to ensure all tabs are in the page's normal tabbing order. The 'home' and 'end' keys will also move focus to the first and last tab respectively.

2. Vertical tabs, all focusable

This example makes for a good accordion...

Apple
An apple is a sweet, edible fruit produced by an apple tree (Malus domestica). Apple trees are cultivated worldwide and are the most widely grown species in the genus Malus. The tree originated in Central Asia, where its wild ancestor, Malus sieversii, is still found today. Apples have been grown for thousands of years in Asia and Europe and were brought to North America by European colonists. Apples have religious and mythological significance in many cultures, including Norse, Greek and European Christian tradition.
Orange
The orange is the fruit of the citrus species Citrus × sinensis in the family Rutaceae, native to China. It is also called sweet orange, to distinguish it from the related Citrus × aurantium, referred to as bitter orange. The sweet orange reproduces asexually (apomixis through nucellar embryony); varieties of sweet orange arise through mutations.
Pear
The pear (/ˈpɛər/) tree and shrub are a species of genus Pyrus /ˈpaɪrəs/, in the family Rosaceae, bearing the pomaceous fruit of the same name. Several species of pear are valued for their edible fruit and juices while others are cultivated as trees.
<div id="fruits" aria-orientation="vertical">
    <div id="apple">Apple</div>
    <div aria-labelledby="apple">...</div>

    <div id="orange">Orange</div>
    <div aria-labelledby="orange">...</div>

    <div id="pear">Pear</div>
    <div aria-labelledby="pear">...</div>
<div>

<script>
    AriaTablist(document.getElementById('fruits'), {
        focusableTabs: true
    });
</script>

3. Horizontal tabs that activate as you navigate through them with any arrow keypresses

Apple
Orange
Pear
An apple is a sweet, edible fruit produced by an apple tree (Malus domestica). Apple trees are cultivated worldwide and are the most widely grown species in the genus Malus. The tree originated in Central Asia, where its wild ancestor, Malus sieversii, is still found today. Apples have been grown for thousands of years in Asia and Europe and were brought to North America by European colonists. Apples have religious and mythological significance in many cultures, including Norse, Greek and European Christian tradition.
The orange is the fruit of the citrus species Citrus × sinensis in the family Rutaceae, native to China. It is also called sweet orange, to distinguish it from the related Citrus × aurantium, referred to as bitter orange. The sweet orange reproduces asexually (apomixis through nucellar embryony); varieties of sweet orange arise through mutations.
The pear (/ˈpɛər/) tree and shrub are a species of genus Pyrus /ˈpaɪrəs/, in the family Rosaceae, bearing the pomaceous fruit of the same name. Several species of pear are valued for their edible fruit and juices while others are cultivated as trees.
<div id="fruits">
    <div aria-controls="apple">Apple</div>
    <div aria-controls="orange">Orange</div>
    <div aria-controls="pear">Pear</div>
<div>

<div id="apple">...</div>
<div id="orange">...</div>
<div id="pear">...</div>

<script>
    AriaTablist(document.getElementById('fruits'), {
        arrowActivation: true,
        allArrows: true
    });
</script>

4. Vertical, all focusable, deletable, multi-selectable tabs, with second and third tab active by default

The deletable option enables tab deletion via the keyboard

Apple
An apple is a sweet, edible fruit produced by an apple tree (Malus domestica). Apple trees are cultivated worldwide and are the most widely grown species in the genus Malus. The tree originated in Central Asia, where its wild ancestor, Malus sieversii, is still found today. Apples have been grown for thousands of years in Asia and Europe and were brought to North America by European colonists. Apples have religious and mythological significance in many cultures, including Norse, Greek and European Christian tradition.
Orange
The orange is the fruit of the citrus species Citrus × sinensis in the family Rutaceae, native to China. It is also called sweet orange, to distinguish it from the related Citrus × aurantium, referred to as bitter orange. The sweet orange reproduces asexually (apomixis through nucellar embryony); varieties of sweet orange arise through mutations.
Pear
The pear (/ˈpɛər/) tree and shrub are a species of genus Pyrus /ˈpaɪrəs/, in the family Rosaceae, bearing the pomaceous fruit of the same name. Several species of pear are valued for their edible fruit and juices while others are cultivated as trees.
<div id="fruits" aria-multiselectable="true" aria-orientation="vertical">
    <div aria-controls="apple">Apple</div>
    <div id="apple">...</div>

    <div aria-controls="orange" aria-selected="true">Orange</div>
    <div id="orange">...</div>

    <div aria-controls="pear" aria-selected="true">Pear</div>
    <div id="pear">...</div>
<div>

<script>
    AriaTablist(document.getElementById('fruits'), {
        deletable: true,
        focusableTabs: true
    });
</script>

5. Horizontal tabs, with second tab open by default but disabled, in RTL mode

  • Apple
  • Orange
  • Pear
An apple is a sweet, edible fruit produced by an apple tree (Malus domestica). Apple trees are cultivated worldwide and are the most widely grown species in the genus Malus. The tree originated in Central Asia, where its wild ancestor, Malus sieversii, is still found today. Apples have been grown for thousands of years in Asia and Europe and were brought to North America by European colonists. Apples have religious and mythological significance in many cultures, including Norse, Greek and European Christian tradition.
The orange is the fruit of the citrus species Citrus × sinensis in the family Rutaceae, native to China. It is also called sweet orange, to distinguish it from the related Citrus × aurantium, referred to as bitter orange. The sweet orange reproduces asexually (apomixis through nucellar embryony); varieties of sweet orange arise through mutations.
The pear (/ˈpɛər/) tree and shrub are a species of genus Pyrus /ˈpaɪrəs/, in the family Rosaceae, bearing the pomaceous fruit of the same name. Several species of pear are valued for their edible fruit and juices while others are cultivated as trees.
<ul id="fruits" dir="rtl">
    <li>
        <div data-controls="apple">Apple</div>
    </li>
    <li>
        <div data-controls="orange" aria-disabled="true" data-selected="true">
            Orange
        </div>
    </li>
    <li>
        <div aria-controls="pear">Pear</div>
    </li>
</ul>

<div id="apple">...</div>
<div id="orange">...</div>
<div id="pear">...</div>

<script>
    AriaTablist(document.getElementById('fruits'), {
        tabSelector: 'div'
    });
</script>

With dir="rtl" set on the main element, or on the document (<html> tag), the horizontal arrow key behaviour will also be reversed (the left arrow will move focus to the next tab, and the right arrow will move focus to the previous).

This example also demonstrates that the HTML structure can be completely flexible, that data-controls can be used to indicate the tab-panel relationships as well as aria-controls, and that data-selected can be used to indicate the starting tab(s) as well as aria-selected.

HTML requirements / Progressive enhancement

When the module is called on an element, the following steps are taken:

  1. The module will search for tab elements using the tabSelector option ('[role="tab"]' by default).
  2. If none are found, all direct children will be processed.
  3. For each assumed tab, the module will check for a matching tabpanel by:
    1. Checking for an aria-controls or data-controls attribute on the tab, and searching for an element with a matching id.
    2. If the tab has an id, searching for an element with an aria-labelledby or data-labelledby attribute that matches that id.
  4. For any tabs that were processed where a matching panel was not found, if they have role="tab" set, the role attribute will be removed to prevent confusion to screen reader users.
  5. The found tabs and associated panels will then have the relevant role and aria- attributes set automatically.

This means your HTML only needs to indicate the relationship between the tabs and panels, and the module will handle the rest:

<div id="tabs">
    <div id="tab-1">Panel 1</div>
    <div aria-controls="panel-2">Panel 2</div>
    <div data-controls="panel-3">Panel 3</div>
<div>

<div aria-labelledby="tab-1">...</div>
<div id="panel-2">...</div>
<div id="panel-3">...</div>

<script>
   AriaTablist(document.getElementById('tabs'));
</script>

So if you need to cater for users without JavaScript, or if the JavaScript fails to load for whatever reason, there won't be any applicable roles set that would confuse a screen reader user.

You can of course include all of the optimal ARIA attributes straight away if you wish, including indicating which tab should be active by default:

<div role="tablist" aria-orientation="horizontal" aria-label="Fruits">
    <div role="tab" tabindex="-1" aria-controls="panel-1" id="tab-1">
        Apple
    </div>
    <div role="tab" tabindex="0" aria-selected="true" aria-controls="panel-2" id="tab-2">
        Orange
    </div>
    <div role="tab" tabindex="-1" aria-controls="panel-3" id="tab-3">
        Pear
    </div>
<div>

<div role="tabpanel" aria-labelledby="tab-1" hidden="hidden" id="panel-1">...</div>
<div role="tabpanel" aria-labelledby="tab-2" id="panel-2">...</div>
<div role="tabpanel" aria-labelledby="tab-3" hidden="hidden" id="panel-3">...</div>

Options

Most of the functionality is assumed from the included ARIA attributes in your HTML, but some basic options are also available:

delay: number
Delay in milliseconds before showing tab(s) from user interaction
Default: 0
deletable: Boolean
Allow tab deletion via the keyboard - can be overridden per tab by setting data-deletable="false"
Default: false
focusableTabs: Boolean
Make all tabs focusable in the normal tabbing order (by setting a tabindex on them), instead of just one
Default: false
focusablePanels: Boolean
Make all tab panels focusable in the normal tabbing order (by setting a tabindex on them)
Default: true
arrowActivation: Boolean
Enable all arrow keys for moving focus between the tabs
Default: false
allArrows: Boolean
Enable all arrow keys for moving focus, instead of checking the aria-orientation value (left and up for previous, right and down for next)
Default: false
tabSelector: string
the selector to use when initially searching for tab elements; if none are found, all direct children of the main element will be processed
Default: '[role="tab"]'
tabindex: number
Value to use when setting tabs or panels to be part of the page's tabbing order
Default: 0
onOpen: Function
Callback each time a tab opens
Default: (panel, tab) => {}
onClose: Function
Callback each time a tab closes
Default: (panel, tab) => {}
onDelete: Function
Callback when a tab is deleted
Default: (tab) => {}
onReady: Function
Callback once ready
Default: (tablist) => {}

All component options that accept a Function will have their context (this) set to include the full autocomplete API (assuming you use a normal function: () {} declaration for the callbacks instead of arrow functions).

API

The returned AriaTablist instance exposes the following API (which is also available on the original element's ariaTablist property):

tabs: HTMLElement[]
The tab elements the module currently recognises
panels: HTMLElement[]
The panel elements the module currently recognises
options: AriaTablistOptions
The current options object
open: (index: number | HTMLElement, focusTab: Boolean = true): void
Trigger a particular tab to open (by index, or element), even if disabled
close: (index: number | HTMLElement, focusTab: Boolean = false): void
Trigger a particular tab to close (by index, or element), even if disabled
delete: (index: number | HTMLElement): void
Delete a particular tab and its corresponding panel (if deletable)
destroy: Function
Destroy the module - does not remove the elements from the DOM
On GitHub