دکمه رادیویی (Radio Group)

مجموعه‌ای از دکمه‌های قابل انتخاب که فقط یکی از آن‌ها می‌تواند در یک زمان انتخاب شود.

نصب (Installation)

1npx @quark-lab/rad-ui add radio-group

نمونه‌ها (Examples)

استفاده پایه (Basic Usage)

استفاده ساده از گروه دکمه‌های رادیویی.

مشاهده کد
1import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
2import { Label } from "@/components/ui/label";
3
4export default function BasicExample() {
5  return (
6    <RadioGroup defaultValue="option-one">
7      <div className="flex flex-row-reverse items-center gap-2">
8        <RadioGroupItem value="option-one" id="option-one" />
9        <Label htmlFor="option-one">گزینه اول</Label>
10      </div>
11      <div className="flex flex-row-reverse items-center gap-2">
12        <RadioGroupItem value="option-two" id="option-two" />
13        <Label htmlFor="option-two">گزینه دوم</Label>
14      </div>
15      <div className="flex flex-row-reverse items-center gap-2">
16        <RadioGroupItem value="option-three" id="option-three" />
17        <Label htmlFor="option-three">گزینه سوم</Label>
18      </div>
19    </RadioGroup>
20  );
21}
22

با توضیحات (With Description)

افزودن توضیحات اضافی برای هر گزینه.

فاصله‌گذاری استاندارد برای اکثر موارد استفاده

فاصله‌گذاری بیشتر برای خوانایی بهتر

فاصله‌گذاری کمتر برای نمایش بیشتر

مشاهده کد
1import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
2import { Label } from "@/components/ui/label";
3
4export default function WithDescriptionExample() {
5  return (
6    <RadioGroup defaultValue="comfortable">
7      <div className="flex flex-row-reverse items-center gap-2">
8        <RadioGroupItem value="default" id="r1" />
9        <div className="flex flex-col items-end">
10          <Label htmlFor="r1">پیش‌فرض</Label>
11          <p className="text-sm text-muted-foreground">
12            فاصله‌گذاری استاندارد برای اکثر موارد استفاده
13          </p>
14        </div>
15      </div>
16      <div className="flex flex-row-reverse items-center gap-2">
17        <RadioGroupItem value="comfortable" id="r2" />
18        <div className="flex flex-col items-end">
19          <Label htmlFor="r2">راحت</Label>
20          <p className="text-sm text-muted-foreground">
21            فاصله‌گذاری بیشتر برای خوانایی بهتر
22          </p>
23        </div>
24      </div>
25      <div className="flex flex-row-reverse items-center gap-2">
26        <RadioGroupItem value="compact" id="r3" />
27        <div className="flex flex-col items-end">
28          <Label htmlFor="r3">فشرده</Label>
29          <p className="text-sm text-muted-foreground">
30            فاصله‌گذاری کمتر برای نمایش بیشتر
31          </p>
32        </div>
33      </div>
34    </RadioGroup>
35  );
36}
37

کنترل شده (Controlled)

کنترل مقدار انتخاب شده با استفاده از React State.

گزینه انتخاب شده: comfortable

مشاهده کد
1import { useState } from "react";
2import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
3import { Label } from "@/components/ui/label";
4
5export default function ControlledExample() {
6  const [selectedOption, setSelectedOption] = useState("comfortable");
7
8  return (
9    <div className="space-y-4">
10      <RadioGroup value={selectedOption} onValueChange={setSelectedOption}>
11        <div className="flex flex-row-reverse items-center gap-2">
12          <RadioGroupItem value="default" id="c1" />
13          <Label htmlFor="c1">پیش‌فرض</Label>
14        </div>
15        <div className="flex flex-row-reverse items-center gap-2">
16          <RadioGroupItem value="comfortable" id="c2" />
17          <Label htmlFor="c2">راحت</Label>
18        </div>
19        <div className="flex flex-row-reverse items-center gap-2">
20          <RadioGroupItem value="compact" id="c3" />
21          <Label htmlFor="c3">فشرده</Label>
22        </div>
23      </RadioGroup>
24      <p className="text-sm text-muted-foreground">
25        گزینه انتخاب شده: {selectedOption}
26      </p>
27    </div>
28  );
29}
30

حالت غیرفعال (Disabled State)

غیرفعال کردن یک گزینه یا کل گروه.

مشاهده کد
1import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
2import { Label } from "@/components/ui/label";
3
4export default function DisabledExample() {
5  return (
6    <RadioGroup defaultValue="option-one">
7      <div className="flex flex-row-reverse items-center gap-2">
8        <RadioGroupItem value="option-one" id="d1" />
9        <Label htmlFor="d1">گزینه فعال</Label>
10      </div>
11      <div className="flex flex-row-reverse items-center gap-2">
12        <RadioGroupItem value="option-two" id="d2" disabled />
13        <Label htmlFor="d2" className="opacity-50">
14          گزینه غیرفعال
15        </Label>
16      </div>
17      <div className="flex flex-row-reverse items-center gap-2">
18        <RadioGroupItem value="option-three" id="d3" />
19        <Label htmlFor="d3">گزینه دیگر</Label>
20      </div>
21    </RadioGroup>
22  );
23}
24

یکپارچگی با فرم (Form Integration)

استفاده از دکمه‌های رادیویی در یک فرم.

دریافت اعلان از طریق ایمیل

دریافت اعلان از طریق پیامک

دریافت اعلان فشاری در مرورگر

مشاهده کد
1import { useState } from "react";
2import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
3import { Label } from "@/components/ui/label";
4
5export default function FormExample() {
6  const [notifyMethod, setNotifyMethod] = useState("email");
7
8  return (
9    <form
10      className="space-y-6"
11      onSubmit={(e) => {
12        e.preventDefault();
13        console.log("Notify method:", notifyMethod);
14      }}
15    >
16      <div className="space-y-3">
17        <Label className="text-base font-semibold">
18          چگونه می‌خواهید مطلع شوید؟
19        </Label>
20        <RadioGroup
21          value={notifyMethod}
22          onValueChange={setNotifyMethod}
23          name="notifyMethod"
24        >
25          <div className="flex flex-row-reverse items-center gap-2">
26            <RadioGroupItem value="email" id="email" />
27            <div className="flex flex-col items-end">
28              <Label htmlFor="email">ایمیل</Label>
29              <p className="text-sm text-muted-foreground">
30                دریافت اعلان از طریق ایمیل
31              </p>
32            </div>
33          </div>
34          <div className="flex flex-row-reverse items-center gap-2">
35            <RadioGroupItem value="sms" id="sms" />
36            <div className="flex flex-col items-end">
37              <Label htmlFor="sms">پیامک</Label>
38              <p className="text-sm text-muted-foreground">
39                دریافت اعلان از طریق پیامک
40              </p>
41            </div>
42          </div>
43          <div className="flex flex-row-reverse items-center gap-2">
44            <RadioGroupItem value="push" id="push" />
45            <div className="flex flex-col items-end">
46              <Label htmlFor="push">اعلان فشاری</Label>
47              <p className="text-sm text-muted-foreground">
48                دریافت اعلان فشاری در مرورگر
49              </p>
50            </div>
51          </div>
52        </RadioGroup>
53      </div>
54      <button
55        type="submit"
56        className="px-4 py-2 bg-primary text-primary-foreground rounded-md hover:bg-primary/90 transition-colors"
57      >
58        ذخیره تنظیمات
59      </button>
60    </form>
61  );
62}
63

مثال‌های پیشرفته (Advanced Examples)

استایل کارتی (Card Style)

سفارشی‌سازی ظاهر گزینه‌ها به صورت کارت.

مشاهده کد
1import { useState } from "react";
2import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
3import { Label } from "@/components/ui/label";
4
5export default function CardStyleExample() {
6  const [plan, setPlan] = useState("free");
7
8  return (
9    <RadioGroup value={plan} onValueChange={setPlan}>
10      <div className="grid gap-4">
11        <div
12          className={`relative flex items-start flex-row-reverse gap-2 p-4 border-2 rounded-lg cursor-pointer transition-colors ${
13            plan === "free"
14              ? "border-primary bg-primary/5"
15              : "border-border hover:border-primary/50"
16          }`}
17          onClick={() => setPlan("free")}
18        >
19          <RadioGroupItem value="free" id="free" className="mt-1" />
20          <div className="flex-1">
21            <Label htmlFor="free" className="cursor-pointer flex flex-col items-end">
22              <div className="font-semibold">رایگان</div>
23              <p className="text-sm text-muted-foreground mt-1">
24                برای شروع کار و آزمایش ویژگی‌ها
25              </p>
26              <p className="text-sm font-medium mt-2">۰ تومان / ماه</p>
27            </Label>
28          </div>
29        </div>
30        <div
31          className={`relative flex items-start flex-row-reverse gap-2 p-4 border-2 rounded-lg cursor-pointer transition-colors ${
32            plan === "pro"
33              ? "border-primary bg-primary/5"
34              : "border-border hover:border-primary/50"
35          }`}
36          onClick={() => setPlan("pro")}
37        >
38          <RadioGroupItem value="pro" id="pro" className="mt-1" />
39          <div className="flex-1">
40            <Label htmlFor="pro" className="cursor-pointer flex flex-col items-end">
41              <div className="font-semibold">حرفه‌ای</div>
42              <p className="text-sm text-muted-foreground mt-1">
43                برای کسب‌وکارهای در حال رشد
44              </p>
45              <p className="text-sm font-medium mt-2">۲۹۹,۰۰۰ تومان / ماه</p>
46            </Label>
47          </div>
48        </div>
49        <div
50          className={`relative flex items-start flex-row-reverse gap-2 p-4 border-2 rounded-lg cursor-pointer transition-colors ${
51            plan === "enterprise"
52              ? "border-primary bg-primary/5"
53              : "border-border hover:border-primary/50"
54          }`}
55          onClick={() => setPlan("enterprise")}
56        >
57          <RadioGroupItem value="enterprise" id="enterprise" className="mt-1" />
58          <div className="flex-1">
59            <Label htmlFor="enterprise" className="cursor-pointer flex flex-col items-end">
60              <div className="font-semibold">سازمانی</div>
61              <p className="text-sm text-muted-foreground mt-1">
62                برای سازمان‌های بزرگ با نیازهای سفارشی
63              </p>
64              <p className="text-sm font-medium mt-2">تماس بگیرید</p>
65            </Label>
66          </div>
67        </div>
68      </div>
69    </RadioGroup>
70  );
71}
72

مرجع API (API Reference)

RadioGroup

پراپ‌های کامپوننت RadioGroup.

پراپ (Prop)نوع (Type)پیش‌فرض (Default)توضیحات (Description)
valuestringundefinedمقدار کنترل شده
defaultValuestringundefinedمقدار پیش‌فرض (غیرکنترل شده)
onValueChange(value: string) => voidundefinedتابع فراخوانی هنگام تغییر مقدار
disabledbooleanfalseغیرفعال کردن تمام گزینه‌ها
namestringundefinedنام فیلد برای ارسال فرم
requiredbooleanfalseالزامی بودن انتخاب
orientation"horizontal" | "vertical""vertical"جهت نمایش گزینه‌ها

RadioGroupItem

پراپ‌های کامپوننت RadioGroupItem.

پراپ (Prop)نوع (Type)پیش‌فرض (Default)توضیحات (Description)
valuestring-مقدار این گزینه (الزامی)
disabledbooleanfalseغیرفعال کردن این گزینه
idstringundefinedشناسه برای ارتباط با Label

دسترسی‌پذیری (Accessibility)

کیبورد (Keyboard)

  • Tab - ورود به گروه یا خروج از آن
  • Space - انتخاب گزینه فعلی
  • Arrow Keys - حرکت بین گزینه‌ها و انتخاب خودکار

نقش ARIA (ARIA Role)

کامپوننت از نقش radiogroup و radio استفاده می‌کند

برچسب‌ها (Labels)

همیشه از Label با ویژگی htmlFor برای هر RadioGroupItem استفاده کنید

مدیریت فوکوس (Focus Management)

از الگوی roving tabindex برای مدیریت فوکوس استفاده می‌شود که فقط یک آیتم در هر زمان قابل فوکوس است

بهترین شیوه‌ها (Best Practices)

برچسب واضح (Clear Labels)

همیشه برچسب‌های واضح و مختصر برای هر گزینه استفاده کنید تا کاربر بتواند به راحتی تصمیم بگیرد

تعداد محدود گزینه‌ها (Limited Options)

برای بیش از ۵-۷ گزینه، از Select یا Combobox استفاده کنید. Radio Group برای تعداد محدود گزینه مناسب است

انتخاب انحصاری (Mutually Exclusive)

فقط برای انتخاب‌های انحصاری استفاده کنید. برای انتخاب‌های چندگانه از Checkbox استفاده کنید

مقدار پیش‌فرض (Default Value)

در بیشتر موارد، یک مقدار پیش‌فرض تنظیم کنید تا کاربر مجبور به انتخاب نباشد (مگر اینکه انتخاب آگاهانه ضروری باشد)