UIDex

الشريحة

Chip / Tag

<button> / role="option"

اسمه كمانشيب، تاج، وسم، شريحة تصفية، شريحة إدخال، كبسولة، tag، pill، filter chip، input chip، token، badge

الشريحة عنصر تحكّم صغير على شكل كبسولة يحمل قيمة واحدة: كلمة مفتاحية، أو فلتر، أو اسم مستلم. وما يجعلها شريحة أنها تفاعلية، فالضغط عليها يغيّر حالة في الصفحة: يشغّل تصفية، أو يختارها، أو يحذفها من قائمة. فإن لم يفعل الضغط عليها شيئاً فهي ليست شريحة مهما كان شكلها. أمّا الوسم (tag أو label) فيشبهها في الشكل تماماً، لكنه بيانات وصفية ساكنة تُقرأ ولا تُضغط، فمكانه <span> لا <button>، ووضعه في زرّ يجعل قارئ الشاشة يعلن عناصر قابلة للنقر لا تفعل شيئاً. والشارة (badge) ليست عنصراً مستقلّاً، بل عدّاد أو حالة ملتصقة بعنصر آخر (أيقونة أو تبويب أو زرّ) تصفه هو، ولا يضغط عليها المستخدم بمفردها. وكلمة pill لا تسمّي مكوّناً كذلك، فهي وصف لشكل لا غير: نصف قطر يساوي نصف الارتفاع، وقد يتّخذه الزرّ والوسم والشريحة على السواء. والقاعدة أن الاسم يتبع السلوك لا الشكل.

لو قلت عليه…

«الحاجات الصغيرة المدوّرة اللي جنبها × تشيلها بيه»«أزرار الفلترة اللي فوق نتايج البحث»«الاسم اللي بيتحوّل لمستطيل صغير أول ما تكتبه في خانة الإيميلات»«التاجات اللي تحت البوست وبتفتح صفحة لما تدوس عليها»«الكبسولة اللي بتتلوّن لما تختارها»

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

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

تصفية النتائج

الكلمات المفتاحية

تصميمإتاحةReact 18

RTLسهم اليمين ينتقل للشريحة السابقة، والـ × عند النهاية المنطقية

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

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

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

ابنِ مجموعة شرائح تصفية مع صفّ شرائح إدخال قابلة للإزالة تحتها. اجعل الحاوية عنصراً بـ role="group" يحمل aria-label يصف أساس التصفية، وامنحها نموذج roving tabindex: شريحة واحدة بـ tabindex="0" والباقي ‎-1، والأسهم تنقل التركيز مع عكس اتجاه ArrowRight/ArrowLeft عندما يكون getComputedStyle(group).direction === "rtl"، و Home و End بلا عكس. كل شريحة تصفية <button type="button"> يحمل aria-pressed، وحالة الاختيار تُميَّز بعلامة صح وحدّ أثخن لا باللون وحده؛ ولو وضعت الشرائح داخل حاوية role="listbox" فاستبدل الزرّ بـ role="option" مع aria-selected. في شرائح الإدخال اجعل زرّ الإزالة شقيقاً لجسم الشريحة لا ابناً له، وأعطه aria-label يذكر القيمة نفسها مثل «إزالة تصميم» ومساحة لمس لا تقلّ عن ٤٤ بكسل، وبعد الحذف انقل التركيز برمجياً إلى الشريحة التالية أو إلى الحاوية، وأعلن الإزالة في منطقة aria-live="polite" موجودة في الصفحة من البداية. لُفّ أي قيمة قد تكون لاتينية بـ <bdi>. استخدم الخصائص المنطقية في كل مكان: padding-inline و margin-inline-end و inset-inline-end و text-align: start و justify-content: flex-start. ولا تكتب left أو right أو padding-left أو justify-content: left. اجعل الصفّ يلتفّ بـ flex-wrap: wrap بدل القصّ بثلاث نقاط، ولا تعرض الوسوم الساكنة كأزرار.

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

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

الأيقونة والـ × داخل الشريحة

ينعكس

الترتيب داخل الشريحة منطقي لا فيزيائي: الأيقونة عند البداية المنطقية والـ × عند النهاية، فتجلس الأيقونة يميناً والـ × يساراً في الصفحة العربية. وحاوية display: flex بـ flex-direction: row تفعل هذا وحدها لأن المحور المضمّن يتبع direction، فلا تضف row-reverse داخل [dir="rtl"] لأنه يعكس الانعكاس ويعيد الـ × إلى جهة الأيقونة. والذي يحتاج تحويلاً هو الحشو غير المتماثل: padding: 4px 12px 4px 8px تصبح padding-block: 4px مع padding-inline: 8px 12px، و margin-right على الأيقونة تصبح margin-inline-end.

التفاف الصفّ ومحاذاته

ينعكس

الالتفاف نفسه ينعكس وحده لأنه يتبع المحور المضمّن، فالفخّ ليس في flex-wrap بل في المحاذاة: justify-content: left و justify-content: right قيمتان فيزيائيتان لا تلتفتان إلى direction، بينما flex-start و start تتبعانه، فاستبدل left بـ flex-start وإلا تكدّست الشرائح على الجهة الخطأ في العربية بينما تبدو سليمة تماماً في الإنجليزية. ونفس القاعدة على text-align: left داخل الشريحة، بديلها text-align: start. وإن كان الصفّ قديماً مبنيّاً على inline-block و float: left فبدّل الـ float إلى inline-start، لأن float فيزيائي بحت ولا يعرف اتجاه الصفحة أصلاً.

أسهم لوحة المفاتيح داخل المجموعة

ينعكس

مفاتيح الأسهم فيزيائية وترتيب الشرائح في الـ DOM منطقي، فالربط بينهما ينقلب: في مجموعة عربية يجب أن ينقل ArrowRight التركيز إلى الشريحة السابقة و ArrowLeft إلى التالية، وإلا مشى التركيز عكس أصابع المستخدم. اقرأ الاتجاه من العنصر نفسه لا من إعداد عام في التطبيق: getComputedStyle(el).direction === "rtl" أو el.matches(":dir(rtl)")، ثم اضرب مقدار الحركة في ‎-1. أمّا Home و End و Tab فلا تنقلب أبداً لأنها منطقية أصلاً: Home هي أوّل شريحة في الـ DOM أياً كان موضعها على الشاشة.

شريط الشرائح القابل للتمرير

ينعكس

لو كان الصفّ شريطاً يُمرَّر أفقياً بدل أن يلتفّ، فحسابات التمرير هي أوّل ما ينكسر: في RTL تساوي scrollLeft صفراً عند بداية القراءة (الحافّة اليمنى) وتصير سالبة كلما تقدّم المستخدم نحو النهاية، وهو السلوك الذي استقرّت عليه المتصفّحات الحديثة، فأي كود يفترض المدى من صفر إلى موجب يمرّر في الاتجاه الخطأ أو لا يتحرّك أصلاً. ولا تحسبها يدوياً: استخدم chip.scrollIntoView({ inline: "nearest", block: "nearest" }) لإحضار شريحة مختارة، و scrollBy({ left: … }) مع عكس إشارة القيمة حسب الاتجاه في أزرار التمرير. وأضف scroll-padding-inline-start حتى لا تلتصق الشريحة بحافّة الشريط عند التمرير التلقائي.

قيمة لاتينية داخل شريحة عربية

لا ينعكس

الشريحة تحمل قيمة تأتي من المستخدم أو من الـ API، وكثيراً ما تكون لاتينية داخل واجهة عربية: «الإطار: React 18» أو «الملف: report-v2.pdf». والمحارف المحايدة (النقطة والشرطة والقوسان والنقطتان والـ × نفسها) لا اتجاه لها، فتأخذ اتجاه ما حولها، فيقع «(12)» في الجهة الخطأ من الاسم اللاتيني أو تلتصق الشرطة بالكلمة العربية التالية. والحلّ عزل لا فرض اتجاه: لُفّ القيمة بـ <bdi>، وهي مكافئة لـ <span dir="auto"> لأن الـ UA يطبّق عليها unicode-bidi: isolate و dir="auto" افتراضاً، أو طبّق unicode-bidi: isolate على span النصّ مباشرة. ولا تستعمل <bdo> هنا: هي تفرض الاتجاه قسراً وتقلب ترتيب المحارف نفسها.

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

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

HTML<button type="button">الشريحة التفاعلية زرّ، و type="button" يمنعها من إرسال النموذج المحيط بها.
ARIAaria-pressed="true"حالة التشغيل/الإيقاف لشريحة تصفية قائمة بذاتها خارج أي listbox.
ARIArole="option" + aria-selectedصالحة فقط داخل أب بـ role="listbox"؛ خارجه تُتجاهل الحالة تماماً.
Material UI<Chip onDelete={fn} />تمرير onDelete وحده هو ما يحوّل الوسم الساكن إلى شريحة قابلة للإزالة، وماتيريال تصنّفها أربعة أنواع: assist و filter و input و suggestion.
Ant Design<Tag closable /> / <Tag.CheckableTag>أنت تسمّيه Tag: العادي ساكن، و CheckableTag هو شريحة الاختيار الفعلية.
shadcn/ui<Badge variant="secondary">السجلّ لا يقدّم سوى Badge ساكنة، فالشريحة التفاعلية تركّبها بنفسك فوقها بزرّ وحالة.
CSSpadding-inline: 0.5rem 0.75remالحشو غير المتماثل حول الأيقونة والـ × ينعكس وحده، بخلاف padding-left/right.

شوف كمان

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