حقل الاختيار (Select)

يتيح لك مكوّن حقل الاختيار أن تختار خيارًا واحدًا من قائمة، أو عدة خيارات. فيه تسمية ونص مساعد وأيقونة في بدايته كما في حقل الإدخال، ويعرض الخيارات المختارة شاراتٍ أو نصًا، بأربعة أحجام وشكلين للزوايا.

التثبيت

bash
npx @smicolon/fasla-ui@latest add select

قبل إضافة أي مكوّن، شغّل الأمر init مرة واحدة في مشروعك. التفاصيل في صفحة التثبيت.

معاينة

المدينة

حيث نوصل طلبك.

الأحجام

أربعة أحجام: ارتفاع الحجم xs هو 28px، والحجم sm هو 32px، والحجم md هو 36px، والحجم lg هو 40px، وهي ارتفاعات حقل الإدخال نفسها. وكما في حقل الإدخال، يتغير الارتفاع والمسافة بين الأيقونة والنص فقط، أما الحشو فهو 12px والأيقونة 16px في كل الأحجام. والنص بحجم 14px، أو 16px على الشاشات التي يقل عرضها عن 768px حتى لا يكبّر نظام iOS الصفحة.

الزوايا

تجعل القيمة standard للخاصية radius الزوايا مستديرة بنصف قطر 8px، وتجعل القيمة rounded الحقل على شكل كبسولة. وتتبع حلقة التركيز شكل الحقل، وتبقى زوايا القائمة 8px في الحالتين.

الحالات

التركيز حالة حقيقية، لا خاصية: انتقل إلى الحقل بمفتاح Tab أو افتحه. يرسم العنصر المُشغِّل حلقة التركيز عند التركيز من لوحة المفاتيح، وطوال بقاء قائمته مفتوحة. وتُظهر الخاصية disabled الحقل كله باهتًا بنصف شفافيته، مع التسمية والنص المساعد.

مفعّل
معطّل

الاختيار المتعدد

تتيح الخاصية multiple اختيار عدة خيارات. تبقى القائمة مفتوحة أثناء الاختيار، وتظهر علامة الصح عند كل خيار مختار. ويعرض العنصر المُشغِّل الخيارات المختارة شاراتٍ، أو سطرًا واحدًا من النص مع القيمة text للخاصية display. تلتف الشارات إلى أسطر أخرى ويتسع الحقل لها. اضغط علامة × في الشارة لإزالتها.

مدن التوصيل

معروضة شاراتٍ.

مدن التوصيل

معروضة سطرًا واحدًا من النص.

التسميات والأيقونات

تعمل التسمية والملاحظة في نهاية سطرها والنص المساعد والأيقونة كما في حقل الإدخال، فيصطف الحقلان جنبًا إلى جنب في النموذج. ضع الأيقونة في الخاصية startIcon، ويضبط الحقل حجمها على حجمه.

اختياري

كما يظهر في بطاقة الهوية.

فرع الاستلام

اختياري

نحتفظ بطلبك 3 أيام.

6 فروع

القائمة

تُفتح القائمة تحت العنصر المُشغِّل، على بعد 4px منه وبعرضه تمامًا. يتميّز الخيار حين يستقر عليه مؤشر الفأرة أو تنتقل إليه بمفاتيح الأسهم. وتدل علامة الصح في نهاية السطر على الخيار المختار، ومكانها محجوز دائمًا فلا يتحرك النص. وفي الصفحات من اليمين إلى اليسار تنتقل علامة الصح وسهم القائمة إلى الطرف الآخر.

الخيارات الطويلة

يلتف الخيار الأطول من عرض القائمة إلى أسطر أخرى داخلها. أما في العنصر المُشغِّل فيبقى الخيار المختار في سطر واحد وينتهي بنقاط.

إتاحة الوصول (accessibility)

  • تمنح مكتبة Base UI العنصر المُشغِّل، وهو عنصر button، الدور combobox، وتجعل القائمة بالدور listbox وفيها الخيارات. ويرسل حقل مخفي القيمة مع النموذج باسم الخاصية name.
  • تُفتح القائمة بمفتاح Enter أو بمفتاح المسافة أو بمفاتيح الأسهم. تنتقل بين الخيارات بمفاتيح الأسهم أو بمفتاح Home أو بمفتاح End، وتقفز إلى خيار يطابق الحرف الذي تكتبه. ويختار مفتاح Enter الخيار، ويغلق مفتاح Escape القائمة ويعيد التركيز إلى العنصر المُشغِّل.
  • تسمّي الخاصية label العنصر المُشغِّل، ويُقرأ النص المساعد معه. وإذا لم تضع تسمية، فأضف السمة aria-label. والضغط على التسمية ينقل التركيز إلى العنصر المُشغِّل دون أن يفتح القائمة.
  • علامة × في الشارة لمؤشر الفأرة، ويتجاوزها قارئ الشاشة. ومن لوحة المفاتيح، افتح القائمة واختر الخيار مرة أخرى لإزالته.
  • يتبع الاتجاه السمة dir في الصفحة، ولا توجد له خاصية. وتأخذ القائمة اتجاه الصفحة ولغتها وخطها من العنصر المُشغِّل، مع أنها تُعرض في نهاية العنصر body.

الخصائص (props)

Select

الخاصيةالنوعالافتراضيالوصف
itemsSelectOption[]لا يوجدالخيارات بصيغة بيانات: value، label، ومعهما disabled عند الحاجة.
childrenReactNodeلا يوجدصفوف SelectItem بدل الخاصية items.
placeholderReactNodeلا يوجدنص يظهر قبل الاختيار.
size"xs" | "sm" | "md" | "lg""md"ارتفاع الحقل: 28 أو 32 أو 36 أو 40px.
radius"standard" | "rounded""standard"شكل الزوايا: بنصف قطر 8px، أو مستديرة بالكامل فيبدو الحقل كبسولة.
multiplebooleanfalseيتيح اختيار أكثر من خيار.
display"badges" | "text""badges"مع الخاصية multiple، يعرض الخيارات المختارة شاراتٍ أو سطرًا واحدًا من النص.
valuestring | string[] | nullلا يوجدالقيمة المختارة، أو القيم مع الخاصية multiple. وتُستخدم مع onValueChange.
defaultValuestring | string[] | nullلا يوجدالقيمة المختارة عند العرض الأول.
onValueChange(value) => voidلا يوجدتُستدعى بالقيمة الجديدة، وعند إزالة شارة أيضًا.
labelReactNodeلا يوجدتسمية الحقل، ترتبط بالعنصر المُشغِّل تلقائيًا.
aria-labelstringلا يوجدالاسم الذي يقرؤه قارئ الشاشة للعنصر المُشغِّل حين لا توجد تسمية ظاهرة.
aria-labelledbystringلا يوجدمعرّف عنصر يسمّي العنصر المُشغِّل بدل الخاصية label.
labelEndReactNodeلا يوجدملاحظة قصيرة في نهاية سطر التسمية، مثل «اختياري».
descriptionReactNodeلا يوجدنص مساعد تحت الحقل، يقرؤه قارئ الشاشة مع الحقل.
descriptionEndReactNodeلا يوجدملاحظة في نهاية سطر النص المساعد، مثل عدد.
startIconReactNodeلا يوجدأيقونة في بداية العنصر المُشغِّل.
disabledbooleanfalseيعطّل الحقل ويُظهر المجموعة كلها باهتة.
readOnlybooleanfalseيعرض القيمة ويمنع تغييرها.
requiredbooleanfalseيُرسل النموذج بعد اختيار قيمة فقط.
namestringلا يوجدالاسم الذي تُرسل به القيمة مع النموذج.
formstringلا يوجدمعرّف النموذج الذي تُرسل معه القيمة، حين يكون الحقل خارجه.
idstringلا يوجدمعرّف العنصر المُشغِّل، لتربطه بعنصر label من عندك.
openbooleanلا يوجديفتح القائمة أو يغلقها حين تتحكم بها.
defaultOpenbooleanfalseيفتح القائمة عند العرض الأول.
onOpenChange(open) => voidلا يوجدتُستدعى عند فتح القائمة أو إغلاقها.
modalbooleantrueيمنع تمرير الصفحة والضغط خارج القائمة ما دامت مفتوحة.
collisionAvoidance{ side, align, fallbackAxisSide }لا يوجدكيف تتجنب القائمة حافة النافذة. تنتقل تلقائيًا فوق العنصر المُشغِّل حين لا يتسع لها المكان تحته، وتبقيها القيمة { side: "none" } تحته.
containerHTMLElementلا يوجدمكان عرض القائمة، والافتراضي العنصر body.
classNamestringلا يوجدأصناف CSS إضافية لمجموعة الحقل.

SelectItem

الخاصيةالنوعالافتراضيالوصف
valuestringلا يوجدالقيمة التي يرسلها هذا الخيار.
labelstringلا يوجدنص للعنصر المُشغِّل والشارات والبحث بالكتابة، حين يعرض الصف أكثر من نص.
disabledbooleanfalseيعرض الخيار ويمنع اختياره.
childrenReactNodeلا يوجدما يعرضه الصف.

الاستخدام

حقل الاختيار البسيط

tsx
import { MapPin } from "lucide-react"
import { Select } from "@/components/ui/select"

const cities = [
  { value: "riyadh", label: "الرياض" },
  { value: "jeddah", label: "جدة" },
  { value: "dammam", label: "الدمام" },
]

export function CityField() {
  return (
    <Select
      name="city"
      label="المدينة"
      placeholder="اختر مدينة"
      startIcon={<MapPin />}
      items={cities}
    />
  )
}

اختيار متعدد مع التحكّم بالقيمة

tsx
"use client"

import * as React from "react"
import { Select } from "@/components/ui/select"

const cities = [
  { value: "riyadh", label: "الرياض" },
  { value: "jeddah", label: "جدة" },
  { value: "dammam", label: "الدمام" },
]

export function DeliveryCities() {
  const [value, setValue] = React.useState<string[]>(["riyadh"])
  return (
    <Select
      multiple
      label="مدن التوصيل"
      placeholder="اختر المدن"
      items={cities}
      value={value}
      onValueChange={setValue}
    />
  )
}

مع صفوف SelectItem

tsx
import { Select, SelectItem } from "@/components/ui/select"

export function BranchField() {
  return (
    <Select label="فرع الاستلام" placeholder="اختر فرعًا">
      <SelectItem value="olaya">فرع العليا</SelectItem>
      <SelectItem value="malqa">فرع الملقا</SelectItem>
      <SelectItem value="nakheel" disabled>
        فرع النخيل
      </SelectItem>
    </Select>
  )
}