برگه (Sheet)
کامپوننت برگه یک پنل کشویی است که از لبههای صفحه (بالا، راست، پایین، چپ) باز میشود و برای نمایش محتوای تکمیلی استفاده میشود.
نصب (Installation)
1npx @quark-lab/rad-ui add sheetنمونهها (Examples)
استفاده پایه (Basic Usage)
سادهترین حالت استفاده از برگه با عنوان و توضیحات.
مشاهده کد
1import {
2 Sheet,
3 SheetContent,
4 SheetDescription,
5 SheetHeader,
6 SheetTitle,
7 SheetTrigger,
8} from "@/components/ui/sheet";
9import { Button } from "@/components/ui/button";
10
11export default function BasicExample() {
12 return (
13 <Sheet>
14 <SheetTrigger asChild>
15 <Button variant="outline">باز کردن برگه</Button>
16 </SheetTrigger>
17 <SheetContent>
18 <SheetHeader>
19 <SheetTitle>عنوان برگه</SheetTitle>
20 <SheetDescription>
21 این یک توضیح کوتاه درباره محتوای برگه است
22 </SheetDescription>
23 </SheetHeader>
24 <div className="py-4">
25 <p className="text-muted-foreground">
26 محتوای اصلی برگه در اینجا قرار میگیرد
27 </p>
28 </div>
29 </SheetContent>
30 </Sheet>
31 );
32}
33جهتهای مختلف (Side Variants)
از پراپ side برای تعیین جهت باز شدن برگه استفاده کنید.
مشاهده کد
1import { Button } from "@/components/ui/button";
2import {
3 Sheet,
4 SheetContent,
5 SheetHeader,
6 SheetTitle,
7 SheetTrigger,
8 SheetDescription,
9} from "@/components/ui/sheet";
10
11const SHEET_SIDES = [
12 { side: "top", label: "بالا" },
13 { side: "right", label: "راست" },
14 { side: "bottom", label: "پایین" },
15 { side: "left", label: "چپ" },
16] as const;
17
18export default function SideExample() {
19 return (
20 <div className="flex flex-wrap gap-2">
21 {SHEET_SIDES.map(({ side, label }) => (
22 <Sheet key={side}>
23 <SheetTrigger asChild>
24 <Button variant="outline">{label}</Button>
25 </SheetTrigger>
26 <SheetContent side={side}>
27 <SheetHeader>
28 <SheetTitle>برگه از سمت {label}</SheetTitle>
29 <SheetDescription>
30 این برگه از سمت {label} باز میشود
31 </SheetDescription>
32 </SheetHeader>
33 <div className="py-4">
34 <p className="text-muted-foreground">
35 محتوای برگه در اینجا قرار میگیرد
36 </p>
37 </div>
38 </SheetContent>
39 </Sheet>
40 ))}
41 </div>
42 );
43}
44با فرم (With Form)
برگه با فرم ورودی برای ویرایش اطلاعات.
مشاهده کد
1import {
2 Sheet,
3 SheetContent,
4 SheetDescription,
5 SheetFooter,
6 SheetHeader,
7 SheetTitle,
8 SheetTrigger,
9 SheetClose,
10} from "@/components/ui/sheet";
11import { Button } from "@/components/ui/button";
12import { Input } from "@/components/ui/input";
13import { Label } from "@/components/ui/label";
14
15export default function WithFormExample() {
16 return (
17 <Sheet>
18 <SheetTrigger asChild>
19 <Button variant="outline">ویرایش پروفایل</Button>
20 </SheetTrigger>
21 <SheetContent>
22 <SheetHeader>
23 <SheetTitle>ویرایش پروفایل</SheetTitle>
24 <SheetDescription>
25 تغییرات خود را اعمال کنید و دکمه ذخیره را بزنید
26 </SheetDescription>
27 </SheetHeader>
28 <div className="grid gap-4 py-4">
29 <div className="grid gap-2">
30 <Label htmlFor="name">نام</Label>
31 <Input id="name" defaultValue="علی کاوسی" />
32 </div>
33 <div className="grid gap-2">
34 <Label htmlFor="username">نام کاربری</Label>
35 <Input id="username" defaultValue="@alikawosi" />
36 </div>
37 </div>
38 <SheetFooter>
39 <SheetClose asChild>
40 <Button variant="outline">انصراف</Button>
41 </SheetClose>
42 <Button type="submit">ذخیره تغییرات</Button>
43 </SheetFooter>
44 </SheetContent>
45 </Sheet>
46 );
47}
48بدون دکمه بستن (No Close Button)
مخفی کردن دکمه X در گوشه بالای برگه با showCloseButton=false.
مشاهده کد
1import {
2 Sheet,
3 SheetContent,
4 SheetDescription,
5 SheetFooter,
6 SheetHeader,
7 SheetTitle,
8 SheetTrigger,
9 SheetClose,
10} from "@/components/ui/sheet";
11import { Button } from "@/components/ui/button";
12
13export default function NoCloseButtonExample() {
14 return (
15 <Sheet>
16 <SheetTrigger asChild>
17 <Button variant="outline">بدون دکمه X</Button>
18 </SheetTrigger>
19 <SheetContent showCloseButton={false}>
20 <SheetHeader>
21 <SheetTitle>بدون دکمه بستن</SheetTitle>
22 <SheetDescription>
23 این برگه دکمه X در گوشه بالا ندارد. برای بستن از دکمه پایین استفاده
24 کنید
25 </SheetDescription>
26 </SheetHeader>
27 <SheetFooter>
28 <SheetClose asChild>
29 <Button variant="outline">بستن</Button>
30 </SheetClose>
31 </SheetFooter>
32 </SheetContent>
33 </Sheet>
34 );
35}
36کنترل شده (Controlled)
کنترل وضعیت باز/بسته برگه با استفاده از state.
وضعیت برگه: بسته
مشاهده کد
1import { useState } from "react";
2import {
3 Sheet,
4 SheetContent,
5 SheetDescription,
6 SheetFooter,
7 SheetHeader,
8 SheetTitle,
9 SheetTrigger,
10} from "@/components/ui/sheet";
11import { Button } from "@/components/ui/button";
12
13export default function ControlledExample() {
14 const [open, setOpen] = useState(false);
15
16 return (
17 <div className="flex flex-col items-center gap-4">
18 <Sheet open={open} onOpenChange={setOpen}>
19 <SheetTrigger asChild>
20 <Button variant="outline">برگه کنترلشده</Button>
21 </SheetTrigger>
22 <SheetContent>
23 <SheetHeader>
24 <SheetTitle>برگه کنترلشده</SheetTitle>
25 <SheetDescription>
26 این برگه با استفاده از state کنترل میشود
27 </SheetDescription>
28 </SheetHeader>
29 <SheetFooter>
30 <Button onClick={() => setOpen(false)}>بستن با کد</Button>
31 </SheetFooter>
32 </SheetContent>
33 </Sheet>
34 <p className="text-sm text-muted-foreground">
35 وضعیت برگه: {open ? "باز" : "بسته"}
36 </p>
37 </div>
38 );
39}
40محتوای قابل اسکرول (Scrollable Content)
برگه با محتوای طولانی که قابل اسکرول است.
مشاهده کد
1import {
2 Sheet,
3 SheetContent,
4 SheetDescription,
5 SheetFooter,
6 SheetHeader,
7 SheetTitle,
8 SheetTrigger,
9 SheetClose,
10} from "@/components/ui/sheet";
11import { Button } from "@/components/ui/button";
12
13export default function ScrollableExample() {
14 return (
15 <Sheet>
16 <SheetTrigger asChild>
17 <Button variant="outline">محتوای طولانی</Button>
18 </SheetTrigger>
19 <SheetContent>
20 <SheetHeader>
21 <SheetTitle>محتوای قابل اسکرول</SheetTitle>
22 <SheetDescription>
23 این برگه محتوای طولانی دارد که قابل اسکرول است
24 </SheetDescription>
25 </SheetHeader>
26 <div className="flex-1 overflow-y-auto py-4">
27 {Array.from({ length: 10 }).map((_, index) => (
28 <p key={index} className="mb-4 leading-relaxed">
29 لورم ایپسوم متن ساختگی با تولید سادگی نامفهوم از صنعت چاپ و با
30 استفاده از طراحان گرافیک است. چاپگرها و متون بلکه روزنامه و مجله
31 در ستون و سطرآنچنان که لازم است و برای شرایط فعلی تکنولوژی مورد
32 نیاز و کاربردهای متنوع با هدف بهبود ابزارهای کاربردی می باشد.
33 </p>
34 ))}
35 </div>
36 <SheetFooter>
37 <SheetClose asChild>
38 <Button variant="outline">بستن</Button>
39 </SheetClose>
40 </SheetFooter>
41 </SheetContent>
42 </Sheet>
43 );
44}
45مثالهای پیشرفته (Advanced Examples)
منوی ناوبری (Navigation Menu)
استفاده از برگه برای منوی ناوبری موبایل.
مشاهده کد
1import {
2 Sheet,
3 SheetContent,
4 SheetHeader,
5 SheetTitle,
6 SheetTrigger,
7} from "@/components/ui/sheet";
8import { Button } from "@/components/ui/button";
9import { Menu } from "lucide-react";
10
11export default function NavigationExample() {
12 return (
13 <Sheet>
14 <SheetTrigger asChild>
15 <Button variant="ghost" size="icon">
16 <Menu className="h-5 w-5" />
17 </Button>
18 </SheetTrigger>
19 <SheetContent side="right">
20 <SheetHeader>
21 <SheetTitle>منوی ناوبری</SheetTitle>
22 </SheetHeader>
23 <nav className="flex flex-col gap-2 py-4">
24 <a href="#" className="px-4 py-2 hover:bg-muted rounded-md transition-colors">
25 خانه
26 </a>
27 <a href="#" className="px-4 py-2 hover:bg-muted rounded-md transition-colors">
28 محصولات
29 </a>
30 <a href="#" className="px-4 py-2 hover:bg-muted rounded-md transition-colors">
31 درباره ما
32 </a>
33 <a href="#" className="px-4 py-2 hover:bg-muted rounded-md transition-colors">
34 تماس با ما
35 </a>
36 </nav>
37 </SheetContent>
38 </Sheet>
39 );
40}
41جلوگیری از بسته شدن (Prevent Close)
جلوگیری از بسته شدن برگه با کلیک خارج یا کلید Escape.
مشاهده کد
1import {
2 Sheet,
3 SheetContent,
4 SheetDescription,
5 SheetFooter,
6 SheetHeader,
7 SheetTitle,
8 SheetTrigger,
9 SheetClose,
10} from "@/components/ui/sheet";
11import { Button } from "@/components/ui/button";
12
13export default function PreventCloseExample() {
14 return (
15 <Sheet>
16 <SheetTrigger asChild>
17 <Button variant="outline">فرم اجباری</Button>
18 </SheetTrigger>
19 <SheetContent
20 onPointerDownOutside={(e) => e.preventDefault()}
21 onEscapeKeyDown={(e) => e.preventDefault()}
22 onInteractOutside={(e) => e.preventDefault()}
23 >
24 <SheetHeader>
25 <SheetTitle>فرم اجباری</SheetTitle>
26 <SheetDescription>
27 این فرم باید تکمیل شود و امکان بستن آن با کلیک خارج یا Escape وجود ندارد
28 </SheetDescription>
29 </SheetHeader>
30 <div className="py-6">
31 <p className="text-muted-foreground">محتوای فرم ضروری...</p>
32 </div>
33 <SheetFooter>
34 <SheetClose asChild>
35 <Button variant="outline">انصراف</Button>
36 </SheetClose>
37 <Button type="submit">ارسال</Button>
38 </SheetFooter>
39 </SheetContent>
40 </Sheet>
41 );
42}
43مرجع API (API Reference)
Sheet
پراپهای کامپوننت Sheet.
| پراپ (Prop) | نوع (Type) | پیشفرض (Default) | توضیحات (Description) |
|---|---|---|---|
open | boolean | undefined | وضعیت باز/بسته بودن (کنترلشده) |
defaultOpen | boolean | false | وضعیت پیشفرض (غیرکنترلشده) |
onOpenChange | (open: boolean) => void | undefined | تابع فراخوانی هنگام تغییر وضعیت |
modal | boolean | true | حالت مودال (بلاک کردن تعامل با پسزمینه) |
SheetContent
پراپهای کامپوننت SheetContent.
| پراپ (Prop) | نوع (Type) | پیشفرض (Default) | توضیحات (Description) |
|---|---|---|---|
side | "top" | "right" | "bottom" | "left" | "right" | جهت باز شدن برگه |
showCloseButton | boolean | true | نمایش دکمه بستن در گوشه بالا |
onEscapeKeyDown | (event) => void | undefined | هندلر فشردن کلید Escape |
onPointerDownOutside | (event) => void | undefined | هندلر کلیک خارج از برگه |
دسترسیپذیری (Accessibility)
کیبورد (Keyboard)
Escape- بستن برگهTab- حرکت بین المانهای قابل فوکوس داخل برگهShift + Tab- حرکت به عقب بین المانها
تله فوکوس (Focus Trap)
وقتی برگه باز است، فوکوس در داخل آن محبوس میشود و کاربر نمیتواند با Tab به خارج از برگه برود
نقشهای ARIA
برگه از role="dialog" و aria-modal="true" استفاده میکند
بهترین شیوهها (Best Practices)
عنوان واضح (Clear Title)
همیشه از SheetTitle استفاده کنید تا کاربران صفحهخوان بتوانند محتوای برگه را درک کنند
انتخاب جهت مناسب (Choose Side Wisely)
جهت راست برای تنظیمات و فرمها، جهت چپ برای منوی ناوبری، و جهتهای بالا/پایین برای اعلانها و فیلترها مناسب هستند
دکمههای اقدام (Action Buttons)
دکمههای اصلی و ثانویه را در SheetFooter قرار دهید. دکمه انصراف همیشه باید وجود داشته باشد
تفاوت با Drawer و Dialog
از Sheet برای پنلهای کناری بدون حرکت لمسی استفاده کنید. از Drawer برای محتوای موبایل با قابلیت کشیدن و از Dialog برای مودالهای مرکزی استفاده کنید