مجموعة اختيار فردي
اختيار واحد من خيارات قليلة معروضة كلها معًا. للمجموعة محطة Tab واحدة، والزر المحدد هو تلك المحطة قبل الترطيب.
client - الحجم لم يُقَس بعد
مجموعة اختيار فردي
client - الحجم لم يُقَس بعداختيار واحد من خيارات قليلة معروضة كلها معًا. للمجموعة محطة Tab واحدة، والزر المحدد هو تلك المحطة قبل الترطيب.
جرّبه
size
orientation
invalid
الشيفرة
radio-group.tsx
import { RadioGroupItem, RadioGroupRoot } from 'topclassui/radio-group'
<div className="grid justify-items-start gap-2">
<span id="radio-group-playground-label" className="text-sm text-body">Billing</span>
<RadioGroupRoot aria-labelledby="radio-group-playground-label" defaultValue="yearly">
<RadioGroupItem value="monthly">Monthly</RadioGroupItem>
<RadioGroupItem value="yearly">Yearly</RadioGroupItem>
<RadioGroupItem value="lifetime">Lifetime</RadioGroupItem>
</RadioGroupRoot>
</div>المجموعة تحمل الحالة والنموذج؛ وكل RadioGroupItem يحمل value الخاص به ونصه فقط.
كل الحالات، بدون تمرير الفأرة
4 حالاتأو استورده من الحزمة
topclassui/radio-group
import { RadioGroupRoot, RadioGroupItem } from 'topclassui/radio-group'ثبّت مرة واحدة:npm i topclassui@beta zod
أمثلة
- لاختيار واحد من خيارات قليلة. للخيارات الكثيرة يناسب Select أكثر؛ ولخيارين إلى خمسة قصيرة في شريط واحد، SegmentedControl.
- داخل نموذج ترسل المجموعة القيمة المحددة، ولا شيء ما دام لا زر محددًا. وقبل الترطيب ترسل القيمة الافتراضية.
orientationقيمتهvertical(عمود) أوhorizontal(صف يلتف). وهو للتخطيط فقط: مفاتيح الأسهم نفسها في الحالتين.- النص الطويل يلتف تحت نفسه بدل أن ينتهي بعلامة حذف: الخيار يُقرأ كاملًا.
- على العنصر، يذهب
styleإلى<label>، ويذهبrefإلى زر الراديو نفسه.
basic
Billing
basic.tsx
import { RadioGroupItem, RadioGroupRoot } from 'topclassui/radio-group'
/** Outside a Field: the group is named by the visible text above it, and each radio by its own text. */
export default function Demo() {
return (
<div className="grid justify-items-start gap-2">
<span id="radio-group-basic-label" className="text-sm text-body">Billing</span>
<RadioGroupRoot aria-labelledby="radio-group-basic-label" defaultValue="yearly">
<RadioGroupItem value="monthly">Monthly</RadioGroupItem>
<RadioGroupItem value="yearly">Yearly</RadioGroupItem>
<RadioGroupItem value="lifetime">Lifetime</RadioGroupItem>
</RadioGroupRoot>
</div>
)
}
horizontal
horizontal.tsx
import { RadioGroupItem, RadioGroupRoot } from 'topclassui/radio-group'
/** orientation="horizontal" lays the radios in a row that wraps on a narrow screen. The arrow keys are the same. */
export default function Demo() {
return (
<RadioGroupRoot aria-label="Size" orientation="horizontal" defaultValue="m">
<RadioGroupItem value="s">Small</RadioGroupItem>
<RadioGroupItem value="m">Medium</RadioGroupItem>
<RadioGroupItem value="l">Large</RadioGroupItem>
<RadioGroupItem value="xl">Extra large</RadioGroupItem>
</RadioGroupRoot>
)
}
form
form.tsx
import { Button } from 'topclassui/button'
import { RadioGroupItem, RadioGroupRoot } from 'topclassui/radio-group'
/** The group carries the name and the default; each radio only its value and its text. It sends plan=pro, before any
* script runs and after. */
export default function Demo() {
return (
<form className="grid justify-items-start gap-3">
<span id="radio-group-form-label" className="text-sm text-body">Plan</span>
<RadioGroupRoot aria-labelledby="radio-group-form-label" name="plan" defaultValue="pro">
<RadioGroupItem value="free">Free</RadioGroupItem>
<RadioGroupItem value="pro">Pro</RadioGroupItem>
<RadioGroupItem value="team">Team</RadioGroupItem>
</RadioGroupRoot>
<Button type="submit">Save</Button>
</form>
)
}
sizes
sizes.tsx
import { RadioGroupItem, RadioGroupRoot } from 'topclassui/radio-group'
/** The five sizes, one group each, the first radio checked. Each target stays 24 px, and 44 px under a finger. */
export default function Demo() {
return (
<div className="grid justify-items-start gap-4">
<RadioGroupRoot size="xs" aria-label="Extra small" defaultValue="on" orientation="horizontal">
<RadioGroupItem value="on">Extra small</RadioGroupItem>
<RadioGroupItem value="off">Off</RadioGroupItem>
</RadioGroupRoot>
<RadioGroupRoot size="sm" aria-label="Small" defaultValue="on" orientation="horizontal">
<RadioGroupItem value="on">Small</RadioGroupItem>
<RadioGroupItem value="off">Off</RadioGroupItem>
</RadioGroupRoot>
<RadioGroupRoot size="md" aria-label="Medium" defaultValue="on" orientation="horizontal">
<RadioGroupItem value="on">Medium</RadioGroupItem>
<RadioGroupItem value="off">Off</RadioGroupItem>
</RadioGroupRoot>
<RadioGroupRoot size="lg" aria-label="Large" defaultValue="on" orientation="horizontal">
<RadioGroupItem value="on">Large</RadioGroupItem>
<RadioGroupItem value="off">Off</RadioGroupItem>
</RadioGroupRoot>
<RadioGroupRoot size="xl" aria-label="Extra large" defaultValue="on" orientation="horizontal">
<RadioGroupItem value="on">Extra large</RadioGroupItem>
<RadioGroupItem value="off">Off</RadioGroupItem>
</RadioGroupRoot>
</div>
)
}
long-content
long-content.tsx
import { RadioGroupItem, RadioGroupRoot } from 'topclassui/radio-group'
/** A choice is read whole: a long text wraps under itself, and a word longer than the line breaks anywhere. */
export default function Demo() {
return (
<RadioGroupRoot aria-label="Delivery" defaultValue="standard">
<RadioGroupItem value="standard">
Standard delivery, three to five working days, left with a neighbour or at the nearest pick-up point if nobody is home
</RadioGroupItem>
<RadioGroupItem value="link">
https://example.com/delivery/options/express-next-day-before-noon-with-signature-and-tracking
</RadioGroupItem>
<RadioGroupItem value="short">Pick up</RadioGroupItem>
</RadioGroupRoot>
)
}
بالعربية، من اليمين إلى اليسار
الفوترة
rtl.tsx
import { TopClassProvider } from 'topclassui/provider'
import { RadioGroupItem, RadioGroupRoot } from 'topclassui/radio-group'
/** Arabic, inside TopClassProvider as the root layout would mount it. Each circle sits at the right, before its text,
* and ArrowRight goes to the radio before. */
export default function Demo() {
return (
<TopClassProvider direction="rtl" locale="ar">
<div dir="rtl" lang="ar" className="grid justify-items-start gap-2">
<span id="radio-group-rtl-label" className="text-sm text-body">الفوترة</span>
<RadioGroupRoot aria-labelledby="radio-group-rtl-label" name="billing" defaultValue="yearly">
<RadioGroupItem value="monthly">شهريًا</RadioGroupItem>
<RadioGroupItem value="yearly">سنويًا</RadioGroupItem>
<RadioGroupItem value="lifetime">مدى الحياة</RadioGroupItem>
</RadioGroupRoot>
</div>
</TopClassProvider>
)
}
الخصائص
RadioGroupRoot
RadioGroupItem
لوحة المفاتيح وإمكانية الوصول
- سمِّ المجموعة بـ
aria-labelأوaria-labelledby: لا تستطيع<label htmlFor>أن تسمّي مجموعة. وكل زر يسمّيه نصه. - مساحة الهدف 24px، و44px تحت مؤشر لمس، مهما كان
sizeالمرسوم: حلقة التركيز تحيط بالدائرة. invalidيضبط aria-invalid على المجموعة: تتحوّل كل دائرة إلى لون الخطر ويزداد سمك خطها، محددة كانت أو لا.
من اليمين إلى اليسار
تقع كل دائرة على اليمين، قبل نصها. وتحت TopClassProvider باتجاه من اليمين إلى اليسار، ينتقل ArrowRight إلى الزر السابق.
الخادم والمتصفح
مكوّن متصفح: يُعرض على الخادم ثم يُرطَّب في المتصفح.
الملفات: index.tsx, client.tsx.
على الشارة: client - الحجم لم يُقَس بعد.