Checkbox
مربّع الاختيار<input type="checkbox">
also calledcheck box، tick box، tri-state checkbox، indeterminate checkbox، select all checkbox، تشيك بوكس، خانة الاختيار، صندوق الاختيار، مربّع التحديد، مربّع صح
A checkbox is a binary field inside a form: selected or not selected, with a value that reaches the server only when the form is submitted. That makes it the control for independent options where more than one may be taken, or none at all. It is not a switch. A switch applies its change at the moment of the press with no save step, while a checkbox stays a draft the user can walk back before submitting. It is not a radio either. Radios force one choice out of a set that rules itself out, whereas every checkbox in a group is fully independent of its neighbours, to the point that required on a checkbox means "this particular box must be ticked" and never "tick one of these". There is a third look called indeterminate, which paints a dash instead of a check, but it is a display state and not a third value: it changes neither checked nor what the form submits.
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.
Where the box sits
mirrorsThe box sits at the logical start of the line, which in Arabic is the right, and the correct DOM order (box first, then text) gives you that in both directions without a single extra rule. Space the two with display: flex and gap, because a margin-right on the box opens the gap on the wrong side once the page flips. Do not add flex-direction: row-reverse under [dir="rtl"] thinking you are fixing direction: the inline axis flipped once already, and the second flip drags the box back to the left while leaving the visual order at odds with Tab order.
The check and the dash
never mirrorsA checkmark does not mirror with page direction: the Bidi_Mirrored property of the check character is No, and the browser painting of a native box does not change in RTL either. A blanket [dir="rtl"] svg { transform: scaleX(-1) } breaks the glyph you drew by hand and leaves it back to front. The indeterminate dash is symmetric about its vertical axis, so the same bad rule leaves no mark on it at all, which is how the bug clears review and turns up later on the checked state alone.
Indenting a nested tree
mirrorsIndent the children of a checkbox tree with padding-inline-start rather than padding-left, so the steps come in from the right in Arabic and from the left in English. A <ul> gets this right on its own, since the browser stylesheet gives it padding-inline-start: 40px; the usual mistake is overriding that with padding-left: 1.5rem, which sends the whole tree back to the wrong side. The vertical guide line joining the children is a border-inline-start, never a border-left.
The focus ring
never mirrorsA ring drawn with outline is direction neutral: outline surrounds all four sides and outline-offset pushes it out from each of them by the same amount, so nothing here needs flipping. Hand-rolled rings are what break: box-shadow: -3px 0 0 var(--ring) has no logical form at all, and a ::before pinned with left: -4px stays on the left after the flip and lands over the text instead of around the box, where inset-inline-start: -4px would have followed the direction. The clipped side moves with it, so a row carrying overflow: hidden, or less padding than the ring is thick, shaves the ring off at the logical start where the box now sits; leave a padding-inline-start wide enough to hold it.
The select column in a table
mirrorsThe checkbox column in a table is the first column, which puts it at the far right in Arabic, and the column order mirrors on its own because the table follows direction. Pinning it with position: sticky and left: 0 leaves it glued to the left edge after the flip, where it floats over the other columns instead of holding the first one, so the value you want is inset-inline-start: 0. The divider marking that column off is a border-inline-end, not a border-right.
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