Skip to content

Tabs Pattern

DodaTech 3 min read

title: "Tabs Pattern — Accessible Tab Interfaces with ARIA Roles" description: "Learn how to build accessible tab interfaces using ARIA roles (tablist, tab, tabpanel) with proper keyboard navigation and screen reader support." weight: 8 date: 2026-06-28 lastmod: 2026-06-28 tags: [accessibility, navigation]


The ARIA tabs pattern creates accessible tabbed interfaces where users can switch between content panels using keyboard navigation and screen reader announcements.

## What You'll Learn

How to implement the ARIA tabs design pattern with proper roles, keyboard interaction, and screen reader support.

## Why It Matters

Tab interfaces save space by showing one panel at a time. Without ARIA, screen reader users cannot identify tabs or navigate between them predictably.

## Real-World Use

A product page has tabs for Description, Specifications, and Reviews. A screen reader user tabs to the tablist, uses arrow keys to navigate between tabs, and the selected panel content is announced.

## Tab Implementation

```html
<div role="tablist" aria-label="Product information">
  <button role="tab" aria-selected="true" aria-controls="panel1" id="tab1">
    Description
  </button>
  <button role="tab" aria-selected="false" aria-controls="panel2" id="tab2">
    Specifications
  </button>
  <button role="tab" aria-selected="false" aria-controls="panel3" id="tab3">
    Reviews
  </button>
</div>

<div role="tabpanel" id="panel1" aria-labelledby="tab1">
  <p>Product description content.</p>
</div>
<div role="tabpanel" id="panel2" aria-labelledby="tab2" hidden>
  <p>Product specifications.</p>
</div>
<div role="tabpanel" id="panel3" aria-labelledby="tab3" hidden>
  <p>Customer reviews.</p>
</div>

Keyboard Navigation

document.querySelector('[role=tablist]').addEventListener('keydown', function(e) {
  const tabs = this.querySelectorAll('[role=tab]');
  const current = this.querySelector('[aria-selected=true]');
  let index = Array.from(tabs).indexOf(current);

  if (e.key === 'ArrowRight') {
    index = (index + 1) % tabs.length;
  } else if (e.key === 'ArrowLeft') {
    index = (index - 1 + tabs.length) % tabs.length;
  } else {
    return;
  }

  e.preventDefault();
  tabs[index].focus();
  tabs[index].click();
});

Tab Activation

tabs.forEach(tab => {
  tab.addEventListener('click', function() {
    const panelId = this.getAttribute('aria-controls');
    const panel = document.getElementById(panelId);

    // Deactivate all tabs and panels
    tabs.forEach(t => t.setAttribute('aria-selected', 'false'));
    panels.forEach(p => p.hidden = true);

    // Activate current
    this.setAttribute('aria-selected', 'true');
    panel.hidden = false;
  });
});

Common Mistakes

Tabs should be buttons unless each tab navigates to a separate URL.

2. Missing aria-controls association

aria-controls on the tab must match the id of the corresponding tabpanel.

3. No aria-labelledby on tabpanel

The tabpanel must reference its tab via aria-labelledby so the screen reader announces the tab name when entering the panel.

4. Hidden panels still focusable

Hidden panels must not contain focusable elements. Use hidden or display: none, not visibility: hidden.

5. Missing aria-orientation

If tabs are vertical, add aria-orientation="vertical" to the tablist and use ArrowUp/ArrowDown instead of Left/Right.

Practice Questions

1. What ARIA role defines the tab container? role="tablist" defines the container that holds the tab elements.

2. How does a screen reader announce the selected tab? It announces "Description, tab, selected" for the active tab.

3. What keyboard keys navigate between tabs? ArrowLeft and ArrowRight for horizontal tabs, ArrowUp and ArrowDown for vertical tabs.

Challenge: Build a complete tab interface with three panels. Implement full keyboard navigation (arrow keys, Home, End) and screen reader testing.

FAQ

Should tabs activate on focus or click?

Activate on click (manual activation) is safer. Activate on focus can be disorienting for keyboard users tabbing through the page.

Can I use a native details/summary instead of tabs?

Only if the content is sequential. Accordion (details/summary) is better for linear reading; tabs are better for switching between views.

Do I need role=presentation on the tablist?

No. The tablist role is sufficient. Avoid redundant role declarations on semantic elements.

How do I make tabs responsive?

On small screens, consider converting tabs to an accordion pattern or a select dropdown for space efficiency.

What happens if JavaScript is disabled?

All panels should be visible as fallback. The tabs pattern degrades to a stacked content layout.

Mini Project

Build a tabbed product information section with Description, Technical Specs, and Reviews tabs. Include full keyboard support and screen reader verification.

What's Next

Learn about Accessible Accordion and how to implement show/hide sections with proper ARIA and keyboard support.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro