قائمة اختيار
اختيار واحد من قائمة بيانات بسيطة. تبقى القائمة المنبثقة داخل الشاشة وتمرّر نفسها، بارتفاع سبعة صفوف افتراضيًا.
client - الحجم لم يُقَس بعد
قائمة اختيار
client - الحجم لم يُقَس بعداختيار واحد من قائمة بيانات بسيطة. تبقى القائمة المنبثقة داخل الشاشة وتمرّر نفسها، بارتفاع سبعة صفوف افتراضيًا.
جرّبه
size
invalid
fullWidth
placement
visibleRows
loadMoreThreshold
الشيفرة
select.tsx
import { Select } from 'topclassui/select'
<div className="grid justify-items-start gap-1.5">
<label htmlFor="select-playground" className="text-sm text-body">Country</label>
<Select id="select-playground" items={COUNTRIES} defaultValue="jo" />
</div>items بيانات بسيطة، فتستطيع صفحة خادم أن تعرض Select: لا تعبر أي دالة إلى المتصفح.
كل الحالات، بدون تمرير الفأرة
4 حالاتPick a paid plan.
أو استورده من الحزمة
topclassui/select
import { Select } from 'topclassui/select'ثبّت مرة واحدة:npm i topclassui@beta zod
أمثلة
itemsيأخذ{ value, label, disabled? }: القيمة هي ما يستلمه النموذج، والتسمية هي ما يظهر في الصف وعلى الزر.- داخل نموذج يرسل القيمة المختارة، وقبل الترطيب يرسل القيمة الافتراضية. وإعادة ضبط النموذج تعيد القيمة الافتراضية.
- تعرض القائمة سبعة صفوف، أو
visibleRows(من 1 إلى 20)، ثم تمرّر داخلها. ولا تعرض الصفوف الظاهرة فقط: للآلاف من الخيارات استخدم Combobox. placementيأخذ القيم المشتركة الاثنتي عشرة، وbottom-startهي الافتراضية؛ تنقلب القائمة عند الحافة وتبقى على بعد 8px داخل الشاشة.- العرض هو عرض Input بنفس
size؛fullWidthيملأ الحاوية، وصنف العرض فيclassNameيقع على الزر داخل الصندوق.
basic
basic.tsx
import { Select } from 'topclassui/select'
const COUNTRIES = [
{ value: 'jo', label: 'Jordan' },
{ value: 'eg', label: 'Egypt' },
{ value: 'ma', label: 'Morocco' },
{ value: 'sa', label: 'Saudi Arabia' },
]
/** A label that points at the trigger by its id, and a list of plain data: the server prints "Jordan" in the trigger. */
export default function Demo() {
return (
<div className="grid justify-items-start gap-1.5">
<label htmlFor="select-basic" className="text-sm text-body">Country</label>
<Select id="select-basic" items={COUNTRIES} defaultValue="jo" />
</div>
)
}
form
form.tsx
import { Button } from 'topclassui/button'
import { Select } from 'topclassui/select'
const COUNTRIES = [
{ value: 'jo', label: 'Jordan' },
{ value: 'eg', label: 'Egypt' },
{ value: 'ma', label: 'Morocco' },
]
/** The Select carries the name and the default. It sends country=jo, before any script runs and after. */
export default function Demo() {
return (
<form className="grid justify-items-start gap-3">
<label htmlFor="select-form" className="text-sm text-body">Country</label>
<Select id="select-form" name="country" items={COUNTRIES} defaultValue="jo" required />
<Button type="submit">Save</Button>
</form>
)
}
sizes
sizes.tsx
import { Select } from 'topclassui/select'
const SIZES = [
{ size: 'xs', label: 'Extra small' },
{ size: 'sm', label: 'Small' },
{ size: 'md', label: 'Medium' },
{ size: 'lg', label: 'Large' },
{ size: 'xl', label: 'Extra large' },
] as const
const PLANS = [{ value: 'free', label: 'Free' }, { value: 'pro', label: 'Pro' }, { value: 'team', label: 'Team' }]
/** The five sizes: the height, the padding and the type step change, and the width follows the type step. */
export default function Demo() {
return (
<div className="grid justify-items-start gap-3">
{SIZES.map(({ size, label }) => (
<Select key={size} aria-label={label} size={size} items={PLANS} defaultValue="pro" />
))}
</div>
)
}
four-rows
four-rows.tsx
import { Select } from 'topclassui/select'
const MONTHS = [
'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December',
].map((label, at) => ({ value: String(at + 1), label }))
/** visibleRows={4}: the list is four rows tall and scrolls through the other eight. */
export default function Demo() {
return (
<div className="grid justify-items-start gap-1.5">
<label htmlFor="select-four-rows" className="text-sm text-body">Month</label>
<Select id="select-four-rows" items={MONTHS} defaultValue="3" visibleRows={4} />
</div>
)
}
sixty-items
sixty-items.tsx
import { Select } from 'topclassui/select'
/** Sixty options, the thirteenth disabled: the list shows seven rows, scrolls inside itself, and opens on the chosen one. */
const OPTIONS = Array.from({ length: 60 }, (_, at) => ({
value: String(at + 1),
label: `Option ${String(at + 1)}`,
...(at === 12 ? { disabled: true } : {}),
}))
export default function Demo() {
return (
<div className="grid justify-items-start gap-1.5">
<label htmlFor="select-sixty" className="text-sm text-body">Sixty options</label>
<Select id="select-sixty" items={OPTIONS} defaultValue="30" />
</div>
)
}
long-content
long-content.tsx
import { Select } from 'topclassui/select'
const LONG = 'Department of Regional Planning, Infrastructure and Sustainable Urban Development, Northern Governorates Office, with responsibility for the coordination of transport, housing, water and energy projects across every municipality of the region, reporting to the minister'
const OFFICES = [
{ value: 'hq', label: 'Head office' },
{ value: 'north', label: LONG },
{ value: 'south', label: 'Southern office' },
]
/** A label far longer than the trigger: it ends in an ellipsis there and in its row, and the list is never wider than
* the screen. The value is never cut: the form still sends north. */
export default function Demo() {
return (
<div className="grid justify-items-start gap-1.5">
<label htmlFor="select-long" className="text-sm text-body">Office</label>
<Select id="select-long" name="office" items={OFFICES} defaultValue="north" />
</div>
)
}
بالعربية، من اليمين إلى اليسار
rtl.tsx
import { TopClassProvider } from 'topclassui/provider'
import { Select } from 'topclassui/select'
const COUNTRIES = [
{ value: 'jo', label: 'الأردن' },
{ value: 'eg', label: 'مصر' },
{ value: 'ma', label: 'المغرب' },
{ value: 'sa', label: 'السعودية' },
]
/** Arabic, inside TopClassProvider as the root layout would mount it. The caret and the tick sit at the left, and
* bottom-start lines the list up with the right edge of the trigger. */
export default function Demo() {
return (
<TopClassProvider direction="rtl" locale="ar">
<div dir="rtl" lang="ar" className="grid justify-items-start gap-1.5">
<label htmlFor="select-rtl" className="text-sm text-body">الدولة</label>
<Select id="select-rtl" name="country" items={COUNTRIES} defaultValue="jo" />
</div>
</TopClassProvider>
)
}
الخصائص
لوحة المفاتيح وإمكانية الوصول
- الاسم مطلوب:
idلتسمية<label htmlFor>، أوaria-label، أوaria-labelledby. الزر هو<button role="combobox">. - ارتفاع الصف 40px، و44px تحت مؤشر لمس، والتسمية الطويلة تنتهي بعلامة حذف في الصف وعلى الزر.
invalidيضبط aria-invalid على الزر، فيتحوّل خطه إلى لون الخطر ويزداد سمكًا.
من اليمين إلى اليسار
يقع السهم وعلامة الاختيار على اليسار، وbottom-start تحاذي القائمة مع الحافة اليمنى للزر. مفاتيح الأسهم عمودية، فلا يتغيّر معناها.
الخادم والمتصفح
مكوّن متصفح: يُعرض على الخادم ثم يُرطَّب في المتصفح.
الملفات: index.tsx, client.tsx.
على الشارة: client - الحجم لم يُقَس بعد.