Enhances the Dialog component to display supporting content for the main interface.
@radix-ui/react-dialog
lucide-react1'use client'
2
3import { Button } from '@/components/ui/button'
4import { Input } from '@/components/ui/input'
5import { Label } from '@/components/ui/label'
6import {
7 Select,
8 SelectContent,
9 SelectItem,
10 SelectTrigger,
11 SelectValue,
12} from '@/components/ui/select'
13import {
14 Sheet,
15 SheetClose,
16 SheetContent,
17 SheetDescription,
18 SheetFooter,
19 SheetHeader,
20 SheetTitle,
21 SheetTrigger,
22} from '@/components/ui/sheet'
23import { Textarea } from '@/components/ui/textarea'
24
25export function AddTaskSheet() {
26 return (
27 <Sheet>
28 <SheetTrigger asChild>
29 <Button variant="outline">Add Task</Button>
30 </SheetTrigger>
31 <SheetContent>
32 <SheetHeader>
33 <SheetTitle>New Task</SheetTitle>
34 <SheetDescription>
35 Fill out the details for your new task and click save
36 when done.
37 </SheetDescription>
38 </SheetHeader>
39 <div className="grid flex-1 auto-rows-min gap-6 px-4">
40 <div className="grid gap-3">
41 <Label htmlFor="task-title">Title</Label>
42 <Input id="task-title" placeholder="Enter task title" />
43 </div>
44 <div className="grid gap-3">
45 <Label htmlFor="task-desc">Description</Label>
46 <Textarea
47 id="task-desc"
48 placeholder="Enter task description"
49 />
50 </div>
51 <div className="grid gap-3">
52 <Label htmlFor="task-date">Assignee</Label>
53 <Select>
54 <SelectTrigger className="w-full">
55 <SelectValue placeholder="Select Assignee" />
56 </SelectTrigger>
57 <SelectContent>
58 <SelectItem value="amelia-nguyen">
59 Amelia Nguyen
60 </SelectItem>
61 <SelectItem value="liam-roberts">
62 Liam Roberts
63 </SelectItem>
64 <SelectItem value="sofia-morales">
65 Sofia Morales
66 </SelectItem>
67 <SelectItem value="marcus-lee">
68 Marcus Lee
69 </SelectItem>
70 <SelectItem value="nora-kim">
71 Nora Kim
72 </SelectItem>
73 <SelectItem value="lucas-martin">
74 Lucas Martin
75 </SelectItem>
76 </SelectContent>
77 </Select>
78 </div>
79 </div>
80 <SheetFooter>
81 <Button type="submit">Save Task</Button>
82 <SheetClose asChild>
83 <Button variant="outline">Cancel</Button>
84 </SheetClose>
85 </SheetFooter>
86 </SheetContent>
87 </Sheet>
88 )
89}
90Install the following dependencies:
Specify the side property on <SheetContent /> to control from which edge of the screen the sheet slides in. Accepted values are top, right, bottom, or left.
1'use client'
2
3import * as React from 'react'
4
5import { Button } from '@/components/ui/button'
6import { Input } from '@/components/ui/input'
7import { Label } from '@/components/ui/label'
8import {
9 Sheet,
10 SheetClose,
11 SheetContent,
12 SheetDescription,
13 SheetFooter,
14 SheetHeader,
15 SheetTitle,
16 SheetTrigger,
17} from '@/components/ui/sheet'
18import { Textarea } from '@/components/ui/textarea'
19
20export function SheetSideDemo() {
21 return (
22 <div className="flex flex-col gap-6">
23 <Sheet>
24 <SheetTrigger asChild>
25 <Button variant={'outline'}>Open Right Sheet</Button>
26 </SheetTrigger>
27 <SheetContent side="right" className="sm:max-w-80 w-full">
28 <SheetHeader>
29 <SheetTitle>Edit Profile</SheetTitle>
30 <SheetDescription>
31 Update your profile information below.
32 </SheetDescription>
33 </SheetHeader>
34 <div className="grid gap-4 px-4 py-2">
35 <div className="grid gap-1">
36 <Label htmlFor="name">Name</Label>
37 <Input id="name" defaultValue="rafael costa" />
38 </div>
39 <div className="grid gap-1">
40 <Label htmlFor="username">Username</Label>
41 <Input id="username" defaultValue="@rafaelcosta" />
42 </div>
43 <div className="grid gap-1">
44 <Label htmlFor="bio">Bio</Label>
45 <Textarea
46 id="bio"
47 placeholder="Tell us about yourself..."
48 />
49 </div>
50 </div>
51 <SheetClose asChild>
52 <Button variant="outline" className="m-4">
53 Save
54 </Button>
55 </SheetClose>
56 </SheetContent>
57 </Sheet>
58
59 <Sheet>
60 <SheetTrigger asChild>
61 <Button variant={'outline'}>Open Left Sheet</Button>
62 </SheetTrigger>
63 <SheetContent side="left" className="sm:max-w-80 w-full">
64 <SheetHeader>
65 <SheetTitle>Edit Profile</SheetTitle>
66 <SheetDescription>
67 Update your profile information below.
68 </SheetDescription>
69 </SheetHeader>
70 <div className="grid gap-4 px-4 py-2">
71 <div className="grid gap-1">
72 <Label htmlFor="name">Name</Label>
73 <Input id="name" defaultValue="rafael costa" />
74 </div>
75 <div className="grid gap-1">
76 <Label htmlFor="username">Username</Label>
77 <Input id="username" defaultValue="@rafaelcosta" />
78 </div>
79 <div className="grid gap-1">
80 <Label htmlFor="bio">Bio</Label>
81 <Textarea
82 id="bio"
83 placeholder="Tell us about yourself..."
84 />
85 </div>
86 </div>
87 <SheetClose asChild>
88 <Button variant="outline" className="m-4">
89 Save
90 </Button>
91 </SheetClose>
92 </SheetContent>
93 </Sheet>
94
95 <Sheet>
96 <SheetTrigger asChild>
97 <Button variant={'outline'}>Open Top Sheet</Button>
98 </SheetTrigger>
99 <SheetContent
100 side="top"
101 className="flex h-84 flex-col justify-between"
102 >
103 <SheetHeader>
104 <SheetTitle>Quick Feedback</SheetTitle>
105 <SheetDescription>
106 Send us your quick feedback.
107 </SheetDescription>
108 </SheetHeader>
109
110 <div className="grid gap-3 px-4">
111 <Label htmlFor="feedback">Feedback</Label>
112 <Textarea
113 id="feedback"
114 placeholder="Type your feedback..."
115 />
116 </div>
117
118 <SheetFooter className="flex justify-end gap-2 px-4 py-2">
119 <Button type="submit">Send</Button>
120 <SheetClose asChild>
121 <Button variant="outline">Cancel</Button>
122 </SheetClose>
123 </SheetFooter>
124 </SheetContent>
125 </Sheet>
126
127 <Sheet>
128 <SheetTrigger asChild>
129 <Button variant={'outline'}>Open Bottom Sheet</Button>
130 </SheetTrigger>
131 <SheetContent
132 side="bottom"
133 className="flex h-84 flex-col justify-between"
134 >
135 <SheetHeader>
136 <SheetTitle>Quick Feedback</SheetTitle>
137 <SheetDescription>
138 Send us your quick feedback.
139 </SheetDescription>
140 </SheetHeader>
141
142 <div className="grid gap-3 px-4">
143 <Label htmlFor="feedback">Feedback</Label>
144 <Textarea
145 id="feedback"
146 placeholder="Type your feedback..."
147 />
148 </div>
149
150 <SheetFooter className="flex justify-end gap-2 px-4 py-2">
151 <Button type="submit">Send</Button>
152 <SheetClose asChild>
153 <Button variant="outline">Cancel</Button>
154 </SheetClose>
155 </SheetFooter>
156 </SheetContent>
157 </Sheet>
158 </div>
159 )
160}
161Use the <SheetTrigger /> component to define how the sheet is opened.
It can wrap various elements such as buttons, icons, links, or even custom components, providing flexibility in user interactions.
1'use client'
2
3import * as React from 'react'
4import { Bell } from 'lucide-react'
5
6import { Button } from '@/components/ui/button'
7import { Input } from '@/components/ui/input'
8import { Label } from '@/components/ui/label'
9import {
10 Sheet,
11 SheetClose,
12 SheetContent,
13 SheetDescription,
14 SheetFooter,
15 SheetHeader,
16 SheetTitle,
17 SheetTrigger,
18} from '@/components/ui/sheet'
19import { Textarea } from '@/components/ui/textarea'
20
21export function SheetContentDemo() {
22 const notifications = [
23 {
24 id: 1,
25 title: 'New message',
26 desc: 'You have a new message from Sarah',
27 time: '5m ago',
28 },
29 {
30 id: 2,
31 title: 'Update available',
32 desc: 'Version 2.0 is now available',
33 time: '1h ago',
34 },
35 {
36 id: 3,
37 title: 'Task completed',
38 desc: 'Your export has finished',
39 time: '3h ago',
40 },
41 ]
42
43 return (
44 <div className="flex flex-col items-center gap-4">
45 <Sheet>
46 <SheetTrigger asChild>
47 <Button variant="outline">Button Sheet</Button>
48 </SheetTrigger>
49 <SheetContent side="right" className="w-80 sm:w-96">
50 <SheetHeader>
51 <SheetTitle>Edit Profile</SheetTitle>
52 <SheetDescription>
53 Make changes to your profile here. Click save when
54 you're done.
55 </SheetDescription>
56 </SheetHeader>
57 <div className="flex flex-col gap-4 px-4 py-4">
58 <div className="flex flex-col gap-2">
59 <Label
60 htmlFor="name"
61 className="text-sm font-medium"
62 >
63 Name
64 </Label>
65 <Input id="name" defaultValue="rafael costa" />
66 </div>
67 <div className="flex flex-col gap-2">
68 <Label
69 htmlFor="email"
70 className="text-sm font-medium"
71 >
72 Email
73 </Label>
74 <Input
75 id="email"
76 type="email"
77 defaultValue="rafael.costa@example.com"
78 />
79 </div>
80 <div className="flex flex-col gap-2">
81 <Label
82 htmlFor="bio"
83 className="text-sm font-medium"
84 >
85 Bio
86 </Label>
87 <Textarea
88 id="bio"
89 defaultValue="I'm a software developer passionate about building great products."
90 rows={4}
91 />
92 </div>
93 </div>
94 <SheetFooter>
95 <SheetClose asChild>
96 <Button variant="outline">Cancel</Button>
97 </SheetClose>
98 <Button>Save Changes</Button>
99 </SheetFooter>
100 </SheetContent>
101 </Sheet>
102
103 {/* Icon Trigger Sheet */}
104 <Sheet>
105 <SheetTrigger asChild>
106 <Button variant="outline" size={'icon'}>
107 <Bell className="size-4" />
108 </Button>
109 </SheetTrigger>
110 <SheetContent side="right" className="w-80 sm:w-96">
111 <SheetHeader>
112 <SheetTitle>Notifications</SheetTitle>
113 <SheetDescription>
114 You have {notifications.length} unread
115 notifications.
116 </SheetDescription>
117 </SheetHeader>
118 <div className="flex flex-col gap-3 px-4">
119 {notifications.map((notif) => (
120 <div
121 key={notif.id}
122 className="border-border flex items-start gap-3 rounded-xl border bg-gray-100 p-3 shadow-sm hover:bg-gray-100/50"
123 >
124 <div className="flex-1">
125 <p className="text-sm font-medium">
126 {notif.title}
127 </p>
128 <p className="text-sm text-gray-600">
129 {notif.desc}
130 </p>
131 <p className="text-gray mt-1 text-xs">
132 {notif.time}
133 </p>
134 </div>
135 </div>
136 ))}
137 {notifications.length === 0 && (
138 <div className="py-8 text-center text-gray-500">
139 No notifications
140 </div>
141 )}
142 </div>
143 <SheetFooter>
144 <Button variant="outline" className="w-full">
145 Clear All
146 </Button>
147 </SheetFooter>
148 </SheetContent>
149 </Sheet>
150 </div>
151 )
152}
153You can open a sheet from within another sheet to handle multi-step workflows or drill-down navigation. This pattern is great for flows like nested settings, detail editing, or multi-step forms.
1'use client'
2
3import { useState } from 'react'
4import { Settings2 } from 'lucide-react'
5
6import { Button } from '@/components/ui/button'
7import { Input } from '@/components/ui/input'
8import { Label } from '@/components/ui/label'
9import {
10 Select,
11 SelectContent,
12 SelectItem,
13 SelectTrigger,
14 SelectValue,
15} from '@/components/ui/select'
16import {
17 Sheet,
18 SheetClose,
19 SheetContent,
20 SheetDescription,
21 SheetFooter,
22 SheetHeader,
23 SheetTitle,
24 SheetTrigger,
25} from '@/components/ui/sheet'
26import { Switch } from '@/components/ui/switch'
27
28export function StoreNestedSheetDemo() {
29 const [trackInventory, setTrackInventory] = useState(true)
30
31 return (
32 <Sheet>
33 <SheetTrigger asChild>
34 <Button variant="outline">Open Product Settings</Button>
35 </SheetTrigger>
36
37 <SheetContent side="right" className="w-96">
38 <SheetHeader>
39 <SheetTitle>Product Settings</SheetTitle>
40 <SheetDescription>
41 Manage your product details, pricing, and stock options.
42 </SheetDescription>
43 </SheetHeader>
44
45 <div className="grid gap-4 px-4 py-4">
46 <div className="grid gap-2">
47 <Label htmlFor="productName">Product Name</Label>
48 <Input
49 id="productName"
50 placeholder="E.g. Classic Cotton T-Shirt"
51 />
52 </div>
53
54 <div className="grid gap-2">
55 <Label htmlFor="price">Price</Label>
56 <Input id="price" placeholder="$25.00" type="number" />
57 </div>
58
59 <div className="grid gap-2">
60 <Label htmlFor="category">Category</Label>
61 <Select>
62 <SelectTrigger className="w-full">
63 <SelectValue placeholder="Select category" />
64 </SelectTrigger>
65 <SelectContent>
66 <SelectItem value="clothing">
67 Clothing
68 </SelectItem>
69 <SelectItem value="accessories">
70 Accessories
71 </SelectItem>
72 <SelectItem value="footwear">
73 Footwear
74 </SelectItem>
75 </SelectContent>
76 </Select>
77 </div>
78
79 {/* Nested Sheet */}
80 <Sheet>
81 <SheetTrigger asChild>
82 <Button variant="secondary">
83 <Settings2 />
84 Inventory Settings
85 </Button>
86 </SheetTrigger>
87
88 <SheetContent side="right" className="w-80">
89 <SheetHeader>
90 <SheetTitle>Inventory Management</SheetTitle>
91 <SheetDescription>
92 Configure stock tracking and warehouse
93 options.
94 </SheetDescription>
95 </SheetHeader>
96
97 <div className="grid gap-4 px-4 py-4">
98 <div className="flex items-center justify-between">
99 <Label htmlFor="inventorySwitch">
100 Track Inventory
101 </Label>
102 <Switch
103 id="inventorySwitch"
104 checked={trackInventory}
105 onCheckedChange={setTrackInventory}
106 />
107 </div>
108
109 {trackInventory && (
110 <div className="grid gap-2">
111 <Label htmlFor="stock">
112 Stock Quantity
113 </Label>
114 <Input
115 id="stock"
116 placeholder="Enter quantity (e.g. 120)"
117 type="number"
118 />
119 </div>
120 )}
121
122 <div className="grid gap-2">
123 <Label htmlFor="warehouse">Warehouse</Label>
124 <Select>
125 <SelectTrigger className="w-full">
126 <SelectValue placeholder="Select warehouse" />
127 </SelectTrigger>
128 <SelectContent>
129 <SelectItem value="main">
130 Main Warehouse
131 </SelectItem>
132 <SelectItem value="east">
133 East Hub
134 </SelectItem>
135 <SelectItem value="west">
136 West Hub
137 </SelectItem>
138 </SelectContent>
139 </Select>
140 </div>
141 </div>
142
143 <SheetFooter className="flex justify-end gap-2 px-4 py-2">
144 <SheetClose asChild>
145 <Button variant="outline">Back</Button>
146 </SheetClose>
147 <SheetClose asChild>
148 <Button>Save</Button>
149 </SheetClose>
150 </SheetFooter>
151 </SheetContent>
152 </Sheet>
153 </div>
154
155 <SheetFooter className="flex justify-end gap-2 px-4 py-2">
156 <SheetClose asChild>
157 <Button variant="outline">Cancel</Button>
158 </SheetClose>
159 <Button type="submit">Save Product</Button>
160 </SheetFooter>
161 </SheetContent>
162 </Sheet>
163 )
164}
165| Prop | Type | Default |
|---|---|---|
| open | boolean | - |
| onOpenChange | (open: boolean) => void | - |
| Prop | Type | Default |
|---|---|---|
| asChild | boolean | false |
| Prop | Type | Default |
|---|---|---|
| side | top,right,bottom,left | right |
| children | (open: boolean) => void | - |
| Prop | Type | Default |
|---|---|---|
| asChild | boolean | false |