Code example
Common baseline
tablist role on the tab container
The element wrapping all tabs must have role="tablist".
tab role on each tab
Each tab element must have role="tab".
tabpanel role on each panel
Each content section must have role="tabpanel" and a unique id.
Tab references its panel via aria-controls
Each tab must have aria-controls pointing to the id of its panel.
Active tab has aria-selected
The active tab must have aria-selected="true"; all others must have aria-selected="false".
Arrow key navigation between tabs
Left/right arrow keys navigate between tabs; Tab moves to the active panel.
Panel is labeled by its tab
Each tabpanel should reference its controlling tab via aria-labelledby.
Use roving tabindex
Only the active tab should have tabindex="0"; inactive tabs should have tabindex="-1".
Home/End keys for first/last tab
Home should jump to the first tab; End should jump to the last.
Do not omit ARIA roles
Implementing tabs with only CSS and JS without ARIA roles makes them invisible to screen readers.
Do not expose inactive panels
Inactive tabpanels must be hidden using the hidden attribute or display:none.
Design system implementations
Additional checks
Connect Tab id and tabpanel aria-labelledby
Explicitly set id="tab-{n}" on each Tab and aria-labelledby="tab-{n}" on each tabpanel. Use the official a11yProps helper for convenience.
Provide aria-label on Tabs
Add aria-label to the Tabs component to describe the purpose of the tab group so screen readers can identify it.
Use disabled prop on inactive Tabs
The disabled prop automatically applies aria-disabled and removes the tab from the focus order.
Code sample
Implementation notes
- –MUI Tabs automatically manages arrow key navigation and roving tabindex.
- –Use the a11yProps helper to consistently generate id and aria-controls pairs for Tab and TabPanel.
- –Wrap the tabpanel body with a hidden attribute rather than conditional rendering so the panel stays in the DOM.