Steps / Stepper
مؤشّر الخطواتaria-current="step"
also calledstepper، step indicator، progress steps، wizard steps، multi-step form، checkout steps، ستيبر، شريط الخطوات، مؤشّر المراحل، خطوات الإنجاز، الويزرد، نموذج متعدّد الخطوات
A stepper is a row of named stages that splits one long task (signing up, checking out, uploading documents) into an ordered sequence, and shows the user where they are and how much is left. What defines it is that the order is enforced and the end is known: the task is finished at the last stage. It is not a breadcrumb trail, because breadcrumbs describe your position in a site hierarchy, not a journey with a start and a finish. Nor is it a progress bar: a progress bar is a percentage with no named stages, while every step here carries a name that says what happens in it. Tabs differ too, because tabs are peers at one level that open in any order, whereas step 4 means nothing before step 3. Pagination is a different thing again, one that walks equal slices of a single collection with nothing to complete. One naming trap: "stepper" is also what many libraries call the small numeric field with + and − buttons, a completely unrelated control.
If you called it…
Live specimen
Interact with the demo. Every part is real and numbered.
الخطوة 2 من 4 · الشحن
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.
Sequence direction
mirrorsThe whole sequence mirrors: step 1 sits at the far right and the last step ends at the left. A flex-direction: row container does this by itself, since the inline axis follows direction. Never add flex-direction: row-reverse under [dir="rtl"], because that double-flips and drops step 1 back on the left. Any connector pinned with position: absolute and left: 50% has to become inset-inline-start: 50%.
How the connector fills
mirrorsThe fill grows from the logical start of the journey, which in Arabic is the right. Implement it as an animated inline-size from 0 to 100% and it mirrors for free, because the fill element is laid out against its parent's logical start edge. transform: scaleX() is physical instead: transform-origin does not accept inline-start at all, and its only values are left/right/percentages. Set transform-origin: right under [dir="rtl"]. The same holds for linear-gradient(to right, …): gradients have no logical keywords, so flip it to to left.
The numerals in the circles
never mirrorsDigits do not mirror and do not need <bdi>: 0-9 carry the bidi class EN, so they always render left-to-right and "10" stays "10" inside an Arabic line, never "01". The decision to make is the numbering system: Latin 1 2 3 or Arabic-Indic ١ ٢ ٣, and never a mix like "خطوة ٢ من 4". Produce both the circle number and the counter text from one source: Intl.NumberFormat("ar-EG") for Arabic-Indic, Intl.NumberFormat("ar-EG-u-nu-latn") for Latin. If you number the circles from CSS, the equivalent is counter(step, arabic-indic). Add font-variant-numeric: tabular-nums so the text stops jumping past ten.
The checkmark never mirrors
never mirrorsA checkmark is not a directional icon: the Bidi_Mirrored property of ✓ is No, and its meaning does not change with page direction. A blanket [dir="rtl"] svg { transform: scaleX(-1) } breaks it and makes it look drawn backwards. Scope the flip to a class such as .icon-directional and put that only on the next/previous chevrons. The same exemption covers the lock icon and the spinner inside a step that is still processing.
The vertical stepper on mobile
mirrorsWhen the steps stack vertically the block axis does not change: step 1 stays at the top in both languages. The rail is what moves, from the left of the text to its right, so use border-inline-start instead of border-left, inset-inline-start instead of left, and padding-inline-start to push the text clear of the circles. A hard-coded left value here leaves the rail running straight through the Arabic step names.
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