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}
90
Install 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}
161
Use 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
66 id="name"
67 defaultValue="rafael costa"
68 className="rounded-md border border-gray-300 px-3 py-2 text-sm"
69 />
70 </div>
71 <div className="flex flex-col gap-2">
72 <Label
73 htmlFor="email"
74 className="text-sm font-medium"
75 >
76 Email
77 </Label>
78 <Input
79 id="email"
80 type="email"
81 defaultValue="rafael.costa@example.com"
82 className="rounded-md border border-gray-300 px-3 py-2 text-sm"
83 />
84 </div>
85 <div className="flex flex-col gap-2">
86 <Label
87 htmlFor="bio"
88 className="text-sm font-medium"
89 >
90 Bio
91 </Label>
92 <Textarea
93 id="bio"
94 defaultValue="I'm a software developer passionate about building great products."
95 className="rounded-md border border-gray-300 px-3 py-2 text-sm"
96 rows={4}
97 />
98 </div>
99 </div>
100 <SheetFooter>
101 <SheetClose asChild>
102 <Button variant="outline">Cancel</Button>
103 </SheetClose>
104 <Button>Save Changes</Button>
105 </SheetFooter>
106 </SheetContent>
107 </Sheet>
108
109 {/* Icon Trigger Sheet */}
110 <Sheet>
111 <SheetTrigger asChild>
112 <Button variant="outline" size={'icon'}>
113 <Bell className="size-4" />
114 </Button>
115 </SheetTrigger>
116 <SheetContent side="right" className="w-80 sm:w-96">
117 <SheetHeader>
118 <SheetTitle>Notifications</SheetTitle>
119 <SheetDescription>
120 You have {notifications.length} unread
121 notifications.
122 </SheetDescription>
123 </SheetHeader>
124 <div className="flex flex-col gap-3 px-4">
125 {notifications.map((notif) => (
126 <div
127 key={notif.id}
128 className="border-border flex items-start gap-3 rounded-xl border bg-gray-100 p-3 shadow-sm hover:bg-gray-100/50"
129 >
130 <div className="flex-1">
131 <p className="text-sm font-medium">
132 {notif.title}
133 </p>
134 <p className="text-sm text-gray-600">
135 {notif.desc}
136 </p>
137 <p className="text-gray mt-1 text-xs">
138 {notif.time}
139 </p>
140 </div>
141 </div>
142 ))}
143 {notifications.length === 0 && (
144 <div className="py-8 text-center text-gray-500">
145 No notifications
146 </div>
147 )}
148 </div>
149 <SheetFooter>
150 <Button variant="outline" className="w-full">
151 Clear All
152 </Button>
153 </SheetFooter>
154 </SheetContent>
155 </Sheet>
156 </div>
157 )
158}
159
You 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 |