This is a small guide to marking up fully accessible tabs. Consider using PostHTML ARIA Tabs as a practical solution.
tablist role to the <ul> to indicate it contains tabs.presentation role to each <li> to bypass its list item state.tab role to each <a> to incidate it is an actual tab.href and aria-controls to each <a> to reference its tab panel.id to each <a> as a reference for its tab panel.aria-selected="true" to the active <a> tab.tabpanel role to each <section> to indicate it is a tab panel.id to each <section> as a reference for its tab.aria-labelledby to each <section> to reference its label.hidden to each inactive <section> to indicate it is hidden.<ul role="tablist"> <li role="presentation"> <a id="foo-tab" href="#foo" role="tab" aria-controls="foo" aria-selected="true">Foo</a> </li> <li role="presentation"> <a id="bar-tab" href="#bar" role="tab" aria-controls="bar">Bar</a> </li> <li role="presentation"> <a id="qux-tab" href="#qux" role="tab" aria-controls="qux">Qux</a> </li> </ul> <section id="foo" role="tabpanel" aria-labelledby="foo-tab"> ... </section> <section id="bar" role="tabpanel" aria-labelledby="bar-tab" hidden> ... </section> <section id="qux" role="tabpanel" aria-labelledby="qux-tab" hidden> ... </section>
[hidden], e.g. [hidden] { display: none; }.<ul> and <li> elements are used for source readability and (to a much lesser extent) progressive enhancement. While both of their implied semantics are overwritten, these elements best represent a collection of items.