UIDex

مؤشّر الخطوات

Steps / Stepper

aria-current="step"

اسمه كمانستيبر، شريط الخطوات، مؤشّر المراحل، خطوات الإنجاز، الويزرد، نموذج متعدّد الخطوات، stepper، step indicator، progress steps، wizard steps، multi-step form، checkout steps

مؤشّر الخطوات صفّ من المحطّات المسمّاة يقسّم مهمّة واحدة طويلة (تسجيل، إتمام طلب، رفع مستندات) إلى مراحل مرتّبة، ويبيّن للمستخدم أين هو الآن وكم بقي أمامه. ما يميّزه أن الترتيب مُلزِم وأن للرحلة نهاية معروفة: المهمّة تنتهي عند آخر خطوة. وهو ليس مسار تنقّل (breadcrumbs)، فالمسار يصف موقعك في شجرة الموقع لا رحلة لها بداية ونهاية. ولا هو شريط تقدّم (progress bar)، لأن الشريط نسبة مئوية بلا محطّات مسمّاة بينما كل خطوة هنا لها اسم يقول ماذا سيحدث فيها. والتبويبات كذلك شيء آخر، لأنها أقران في نفس المستوى تُفتح بأي ترتيب، أمّا الخطوة الرابعة فلا معنى لها قبل الثالثة. ويختلف عنه ترقيم الصفحات، الذي يتنقّل بين شرائح متساوية من مجموعة واحدة ولا يوجد فيه شيء «يكتمل». ويبقى التباس لفظي شائع: كلمة stepper تُطلق أيضاً على حقل الرقم الصغير بزرّي + و − (number stepper)، وهو عنصر مختلف تماماً لا علاقة له بالخطوات.

لو قلت عليه…

«الدواير المرقّمة اللي فوق الفورم»«الحتّة اللي بتقول خطوة ٢ من ٤»«الدواير اللي بتتحوّل علامة صح لما تخلّص»«الخط اللي واصل بين المراحل في صفحة الدفع»«شريط المراحل بتاع التسجيل»

العيّنة الحيّة

تفاعل مع الديمو. كل الأجزاء حقيقية ومرقّمة.

الخطوة 2 من 4 · الشحن

RTLالخطوة الأولى تبدأ من اليمين، وعلامة الصح لا تنعكس

تشريح العنصر: كل جزء واسمه

مرّر على أي سطر ليتحدّد مكانه في الديمو فوق.

برومبت البناء

ابنِ مؤشّر خطوات أفقياً لمهمّة من أربع مراحل. اجعل الحالة كلها مشتقّة من فهرس واحد صفري الأساس currentStep: الخطوة مكتملة إذا index < currentStep، وحالية إذا index === currentStep، وقادمة إذا كانت أكبر، ولا تحتفظ بأعلام isDone و isActive منفصلة. الهيكل <ol> يحمل aria-label، وفي كل <li> دائرة مؤشّر بـ aria-hidden="true" تعرض الرقم أو علامة صح، وعنوان قصير، ونصّ مخفيّ بصرياً يذكر الحالة. ضع aria-current="step" على الخطوة الحالية وحدها، واجعل الخطوات المكتملة أزراراً قابلة للرجوع والخطوات القادمة معطّلة بـ disabled. اجعل خطّ الوصل عنصراً بـ aria-hidden="true" يمتلئ بتحريك inline-size من صفر إلى ١٠٠٪ لا بـ scaleX. استخدم الخصائص المنطقية في كل مكان (margin-inline و padding-inline و inset-inline-start و border-inline-start)، ولا تكتب left أو right أو margin-left. ولّد كل الأرقام من Intl.NumberFormat واحد حتى لا يختلط الترقيم اللاتيني بالهندي، ولا تعكس علامة الصح في RTL بل اقصر scaleX(-1) على أسهم التنقّل. تحقّق من صحّة الخطوة قبل السماح بالانتقال، واحفظ ما أدخله المستخدم عند الرجوع للخلف.

سلوكه في الاتجاه من اليمين لليسار

الجزء ده حصري عندنا.

اتجاه التسلسل

ينعكس

التسلسل كله ينعكس: الخطوة الأولى تجلس في أقصى اليمين والأخيرة عند اليسار. حاوية flex-direction: row تفعل هذا وحدها لأن اتجاه المحور المضمّن يتبع direction، فلا تضف flex-direction: row-reverse داخل [dir="rtl"]؛ فهو يعكس الانعكاس ويعيد الخطوة الأولى إلى اليسار. وأي خطّ وصل مثبّت بـ position: absolute مع left: 50% يجب أن يصير inset-inline-start: 50%.

امتلاء خطّ الوصل

ينعكس

الامتلاء يبدأ من بداية الرحلة المنطقية، أي من اليمين في العربية. لو نفّذته بعرض متغيّر (inline-size من صفر إلى ١٠٠٪) انعكس وحده بلا سطر إضافي، لأن عنصر الامتلاء يستقرّ عند الحافّة المنطقية الأولى لأبيه. أمّا transform: scaleX() فتحجيم على محور فيزيائي. خاصية transform-origin لا تقبل inline-start أصلاً؛ قيمها المسموحة left/right والنِّسَب فقط. اضبطها على transform-origin: right داخل [dir="rtl"]. ونفس القاعدة تسري على linear-gradient(to right, …): التدرّجات لا تعرف الكلمات المنطقية، فاقلبها إلى to left عند الانعكاس.

الأرقام داخل الدوائر

لا ينعكس

الأرقام لا تنعكس ولا تحتاج إلى <bdi>: محارف 0-9 تنتمي إلى صنف bidi يُسمّى EN، فتُرسم يساراً إلى يمين دائماً، و«10» تبقى «10» ولا تنقلب إلى «01» داخل سطر عربي. والقرار المطلوب هنا هو نظام الترقيم: إمّا لاتيني 1 2 3 أو هندي ١ ٢ ٣، ولا تخلط بينهما فتكتب «خطوة ٢ من 4». ولّد رقم الدائرة ونصّ العدّاد من مصدر واحد: Intl.NumberFormat("ar-EG") للأرقام الهندية أو Intl.NumberFormat("ar-EG-u-nu-latn") للاتينية، ولو رقّمت الدوائر من CSS فالمكافئ هو counter(step, arabic-indic). وأضف font-variant-numeric: tabular-nums حتى لا يقفز النصّ عند تجاوز العشرة.

علامة الصح لا تنعكس

لا ينعكس

علامة الصح ليست أيقونة اتجاهية: خاصية Bidi_Mirrored للمحرف ✓ قيمتها No، ومعناها لا يتغيّر مع اتجاه الصفحة. والقاعدة الشاملة [dir="rtl"] svg { transform: scaleX(-1) } تكسرها وتجعلها تبدو كأنها مرسومة بالعكس. اقصر القلب على صنف مخصّص مثل .icon-directional تضعه على أسهم «التالي» و«السابق» وحدها. نفس الاستثناء ينطبق على أيقونة القفل ورمز التحميل الدوّار داخل خطوة قيد المعالجة.

الشكل الرأسي على الموبايل

ينعكس

عند تكديس الخطوات رأسياً لا يتغيّر المحور الكتلي: الخطوة الأولى تبقى في الأعلى في اللغتين. الذي ينتقل هو الخطّ الرأسي الواصل بين الدوائر، فهو يتحوّل من يسار النصّ إلى يمينه. استخدم border-inline-start بدل border-left، و inset-inline-start بدل left، و padding-inline-start لإزاحة النصّ عن الدوائر. أي قيمة left ثابتة هنا ستترك الخطّ يمرّ فوق نصّ الخطوات في العربية.

أسماؤه في الكود

كل سطر هو كلمة مكتبة واحدة عن نفس الشيء. خد السطر اللي بيكلّم مشروعك.

ARIAaria-current="step"العلامة الوحيدة التي تقول أي خطوة هي الحالية، ولا تُوضع إلا على عنصر واحد.
HTML<ol> + <li>قائمة مرتّبة لأن الترتيب جزء من المعنى، لا مجرّد صفّ من divs.
Material UI<Stepper activeStep={1}>فهرس صفري واحد يشتقّ منه كل <Step> حالته؛ و orientation="vertical" للموبايل.
Ant Design<Steps current={1} items={…} />يضيف status="error" لخطوة فشل التحقّق فيها، وهي حالة رابعة ينساها أغلب التنفيذ اليدوي.
Chakra UIuseSteps({ index, count })الخطّاف يعيد activeStep و setActiveStep، فيبقى مصدر الحقيقة رقماً واحداً.
shadcn/uidata-[state=completed]:لا يوجد Stepper جاهز في المكتبة، فتُركّبه من <ol> وسمة data-state تُشتقّ من الفهرس.
CSScounter(step, arabic-indic)ترقيم الدوائر من CSS مع نظام أرقام صريح بدل كتابة الأرقام يدوياً في الـ markup.

شوف كمان

آخر تحديث · 2026-08-19