Segmented Control
الشريط المقسّمrole="radiogroup"
also calledsegmented button، segmented picker، toggle group، joined button group، UISegmentedControl، pill switcher، سيجمنتد كنترول، المتحكّم المقسّم، مفتاح مقسّم، أزرار ملتحمة، شريط اختيار مضغوط، تبويبات مصغّرة
A segmented control is a row of options joined inside one frame, where exactly one is chosen and the selection background moves to whichever option you press. Its job is to pick a value, so its semantics are the semantics of a radio group: role="radiogroup" on the container, role="radio" with aria-checked on each segment. It is not tabs. A tab carries role="tab" and aria-selected and points with aria-controls at a panel that appears and disappears with it, while a segmented control often has no panel under it at all, and its whole effect may be re-sorting a table already on screen or changing the date range of a chart. A toolbar is a different thing again: its buttons are independent actions, none of them holds a selected state, and nothing stops the user pressing two in the same second. Nor is it a button group, where shape is all that joins the buttons and each one does something different; the segments here are mutually exclusive values of one field that knows which of them is current. The test that settles it in review: if a full panel of content with its own heading sits underneath, those are tabs, and if the result is a single value read from a variable or submitted with a form, that is a segmented control.
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.
Segment order
mirrorsDOM order does not change; the inline axis is what flips, so the first option lands at the right end of the strip in Arabic and the last at the left. A flex or grid row does this by itself, so do not add flex-direction: row-reverse or an order property under [dir="rtl"]. The second flip puts the visual order back where it started and leaves what the eye sees disagreeing with where Tab goes. The one thing left to mirror by hand is a glyph that draws a direction of its own: text alignment icons are stacked lines flush to one side, align-to-start sits flush right in Arabic, so flip those glyphs with transform: scaleX(-1) under [dir="rtl"] or ship a second SVG.
Moving the indicator
mirrorstransform is a physical property with no logical counterpart anywhere in CSS. The common bug is anchoring the capsule with inset-inline-start: 0 and then moving it with translateX(calc(var(--i) * 100%)): the anchor moved to the right edge of the strip in Arabic while the translation still pushes rightward, so the capsule leaves the strip on the first selection. Sign the translation instead: translateX(calc(var(--i) * 100% * var(--dir))) with --dir set to -1 under [dir="rtl"]. The alternative that needs no variable is to anchor with physical left: 0 and measure the segment with offsetLeft, so both halves are physical. Mixing one logical property with one physical one is what breaks it.
The end corners
mirrorsThe strip is rounded at its two ends only, and the middle segments have square corners. rounded-l and rounded-r, meaning border-top-left-radius and its siblings, pin the rounding to the physical left and right, so in Arabic the first segment comes out square on the outside and rounded on the inside. Use border-start-start-radius and border-end-start-radius on the first segment and border-start-end-radius and border-end-end-radius on the last: the first word names the block axis, the second the inline axis, and in Tailwind they are rounded-s-* and rounded-e-*. :first-child remains the correct selector, because it follows DOM order and DOM order is logical-start order.
The arrow keys
mirrorsIn a radio group an arrow moves focus and changes the value in the same keystroke, and in Arabic the key that means next is ArrowLeft. Do not count on the engine to swap the two for you: Chromium reads the computed direction of the input and flips ArrowLeft and ArrowRight under rtl, while WebKit still treats ArrowRight as next whatever the direction is, so the same markup steps backwards in Safari. Read the direction with getComputedStyle(el).direction inside a keydown listener and swap the keys there with preventDefault, whether you drive the group yourself or patch native radio inputs. ArrowUp and ArrowDown never swap, because the block axis does not flip for Arabic.
Latin labels
never mirrorsThe labels on this control are short, and many are pure Latin: PNG and SVG, 1D and 1W, USD. A Latin word on its own renders correctly, but a neutral character next to it takes the paragraph direction and jumps to the other end of the label, so +20% inside an Arabic strip appears on screen as 20%+. Isolate each label on its own with dir="ltr" on its element or with <bdi>, and do not fix it by putting dir="ltr" on the whole strip, which reverses the order of the segments along with it.
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