Tabs
التبويباتrole="tablist"
also calledtabbed interface، tab group، tablist، tabpanel، tabbed panels، tab control، تابس، التابات، الألسنة، علامات التبويب، شريط التبويبات
Tabs are a row of labels where each label reveals one panel of content in the same slot, and exactly one panel is visible at a time. The defining condition is that the panels are equal siblings, at the same level with no order between them, and that moving between them costs nothing and loses nothing the user typed. Tabs are not a stepper, because steps run in order from a start to an end and carry a completion state, while tabs are never "finished" and nobody has to visit them all. They are not a segmented control either, since a segmented control picks a value for one field and is usually built on radiogroup rather than tablist, whereas a tab swaps an entire panel of content. The biggest difference of all is with links: anything that changes the URL and loads a new page is a navigation link rather than a tab. It stays an <a href> inside <nav>, and putting role="tab" on it breaks both open-in-new-tab and the back button. As a working rule, if the address bar changes it is navigation, and if only the region below changes it is a tab.
If you called it…
Live specimen
Interact with the demo. Every part is real and numbered.
Anatomy: every part, named
Hover a row to locate it in the demo above.
Build prompt
How it behaves right-to-left
This section is ours alone.
The arrow keys swap
mirrorsFor a horizontal tablist the ARIA pattern says ArrowRight moves to the next tab in LTR. In RTL that meaning inverts, so ArrowLeft becomes "next" and ArrowRight becomes "previous". Read direction at runtime from getComputedStyle(list).direction or list.matches(":dir(rtl)") and multiply your step by -1. Never infer it from the UI language, since any single container can be flipped on its own. Home and End do not swap: Home is always the first tab in DOM order, which in Arabic is the rightmost one.
The active underline
mirrorsoffsetLeft measures from the left edge whatever the direction, so a bar position derived from it lands under the wrong tab in RTL. Measure from the logical start instead: in LTR tab.getBoundingClientRect().left − list.left, in RTL list.right − tab.right. Then move the bar with inset-inline-start, or with translateX multiplied by a --dir variable set to -1 under [dir="rtl"], because translateX itself is physical and does not mirror with the page.
Scrolling an overflowing strip
mirrorsThe strip rests at its logical start, which in Arabic is the right edge. In current browsers scrollLeft is 0 at that edge and goes negative as you scroll leftwards, so a "next" button written as el.scrollLeft += 200 scrolls the wrong way, and any comparison against the scroll offset has to go through Math.abs. Use el.scrollBy({ left: delta * dir }) or, better, scrollIntoView({ inline: "nearest" }), which works on the logical axis. Also replace scroll-padding-left with scroll-padding-inline-start.
The scroll-shadow gradients
mirrorsto right and to left are always physical, because linear-gradient accepts no logical direction keywords. The fade that says "there is more" will therefore not mirror itself, however the page direction is set. Anchor the two overlays with inset-inline-start and inset-inline-end so they move to the correct side on their own, then flip the gradient angle under [dir="rtl"] or feed it from a --fade-angle variable. The same limit applies to mask-image if you fade by masking instead.
What must never flip
never mirrorsDo not reverse the tab order with flex-direction: row-reverse. direction: rtl alone already puts the first tab on the right, whereas row-reverse flips the picture and leaves DOM order untouched. The spec states outright that flexbox visual reordering does not affect navigation order, so the arrow keys end up moving against what the eye sees. Likewise aria-orientation describes the layout axis, not the language, so it stays "horizontal" in Arabic. Neutral tab icons (a settings gear, a cart, a bell) never mirror.
In code
Each row is one framework's word for the same thing. Take the row your project speaks.
See also
Updated · 2026-08-19