Radio Group
مجموعة أزرار الاختيارrole="radiogroup"
also calledradio buttons، radiogroup، option buttons، single choice group، radio list، mutually exclusive options، راديو بتن، أزرار الراديو، أزرار الاختيار، مجموعة الخيارات، اختيار واحد من متعدّد، راديو جروب
A radio group is one control holding options that rule each other out, so at most one of them is selected at a time. A single radio means nothing on its own: what makes the options exclusive is belonging to one group, not the round shape. It is not a set of checkboxes, since each checkbox is an independent boolean read by itself, and the user can tick as many or as few of them as they want. It is not a select either. A select does the same job in less room by hiding the options behind a click, while a radio group puts every option in front of the eye so they can be compared before one is picked, which is why it suits roughly seven options and a select takes over above that. It is also not a segmented control, which is a compact shape for the same single choice, joining the options into one strip, usually to switch a view the user is already looking at. Two checks settle it in review: if two answers can be true at once this is not a radio group, and if "none" is a legitimate answer the group needs an explicit None option or a Clear button, because a second press on the chosen radio does not clear it.
If you called it…
Live specimen
Interact with the demo. Every part is real and numbered.
القيمة المرسلة مع النموذج: shipping=express
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.
What the left and right arrows mean
mirrorsIn a horizontal group the two arrows swap meaning with direction: ArrowRight is "next" in LTR, while in RTL ArrowLeft becomes next and ArrowRight becomes previous, exactly as in a tab strip. Chromium already applies that to a native <input type="radio">, where ArrowLeft under direction: rtl moves to the next input in source order and selects it, while a group hand-built from role="radio" inherits none of it: read the direction at runtime with group.matches(":dir(rtl)") or getComputedStyle(group).direction, then multiply the step by -1 rather than inferring it from the UI language, since one container can be flipped on its own. ArrowUp and ArrowDown never swap, because only the inline axis mirrors and the block axis runs top to bottom in both languages.
Where the circle sits
mirrorsThe circle sits at the logical start of the option, on the right in Arabic and on the left in English: make the option row a flex container with gap and let DOM order do the rest, or use padding-inline-start instead of padding-left when the circle is drawn with ::before. Help text under the label is indented with margin-inline-start so it lines up with the first letter of the label rather than the edge of the circle, and a margin-left here pushes it to the wrong side the moment the page flips. Hiding the real input with position: absolute; left: -9999px is free in LTR and adds a horizontal scrollbar in RTL: measured in Chrome, one such input takes a 300px scroll container from a 300px scroll width to about 10,000px, because leftward overflow is scrollable under direction: rtl and clipped under ltr, so clip the input in place with a 1px box and clip-path: inset(50%).
How a horizontal group wraps
mirrorsA horizontal group fills from the right in Arabic and starts its second line from the right on wrap, which is what flex-wrap already does under direction: rtl. Do not write flex-direction: row-reverse to correct the direction: the inline axis has flipped once already, and the second flip leaves visual order disagreeing with DOM order, so the arrow keys move against what the eye sees. Grid follows the same inline axis, so grid-column: 1 is the rightmost column in Arabic, and the numbering should be used as it comes instead of reversed by hand.
The travelling indicator
mirrorsWhen the group is drawn as a joined strip with an indicator sliding behind the selected option, that indicator travels along the logical axis, right to left in Arabic, and offsetLeft cannot express it because it measures from the left edge whatever the direction. Measure from the logical start instead: in RTL that is group.getBoundingClientRect().right minus item.right, and in LTR it is item.left minus group.left. Then move it with inset-inline-start, or with translateX multiplied by a --dir variable set to -1 under [dir="rtl"], because transform is physical and CSS gives it no logical counterpart.
What stays in DOM order
never mirrorsThe flip is visual only and does not touch DOM order, so "the first option" is still the first element in the source, which in a horizontal Arabic group is the rightmost one. The entry point when nothing is selected yet is that same element, arrow wraparound follows source order and therefore throws focus from the option at the visual far left back to the one at the far right, and Home and End mean first and last in source order too. name and value are data rather than layout, so they do not change with direction, field order in FormData follows the source instead of the screen, and the circle with its dot is symmetrical about its vertical axis, which keeps it out of any blanket scaleX(-1) rule you apply to icons.
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