@neynar/ui 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/context7.json +17 -0
- package/llm/components/accordion.llm.md +205 -0
- package/llm/components/alert-dialog.llm.md +289 -0
- package/llm/components/alert.llm.md +310 -0
- package/llm/components/aspect-ratio.llm.md +110 -0
- package/llm/components/avatar.llm.md +282 -0
- package/llm/components/badge.llm.md +185 -0
- package/llm/components/blockquote.llm.md +86 -0
- package/llm/components/breadcrumb.llm.md +245 -0
- package/llm/components/button-group.llm.md +248 -0
- package/llm/components/button.llm.md +247 -0
- package/llm/components/calendar.llm.md +252 -0
- package/llm/components/card.llm.md +356 -0
- package/llm/components/carousel.llm.md +281 -0
- package/llm/components/chart.llm.md +278 -0
- package/llm/components/checkbox.llm.md +234 -0
- package/llm/components/code.llm.md +75 -0
- package/llm/components/collapsible.llm.md +271 -0
- package/llm/components/color-mode.llm.md +196 -0
- package/llm/components/combobox.llm.md +346 -0
- package/llm/components/command.llm.md +353 -0
- package/llm/components/context-menu.llm.md +368 -0
- package/llm/components/dialog.llm.md +283 -0
- package/llm/components/drawer.llm.md +326 -0
- package/llm/components/dropdown-menu.llm.md +404 -0
- package/llm/components/empty.llm.md +282 -0
- package/llm/components/field.llm.md +303 -0
- package/llm/components/first-light.llm.md +129 -0
- package/llm/components/hover-card.llm.md +278 -0
- package/llm/components/input-group.llm.md +334 -0
- package/llm/components/input-otp.llm.md +270 -0
- package/llm/components/input.llm.md +197 -0
- package/llm/components/item.llm.md +347 -0
- package/llm/components/kbd.llm.md +221 -0
- package/llm/components/label.llm.md +219 -0
- package/llm/components/menubar.llm.md +378 -0
- package/llm/components/navigation-menu.llm.md +320 -0
- package/llm/components/pagination.llm.md +337 -0
- package/llm/components/popover.llm.md +278 -0
- package/llm/components/progress.llm.md +259 -0
- package/llm/components/radio-group.llm.md +269 -0
- package/llm/components/resizable.llm.md +222 -0
- package/llm/components/scroll-area.llm.md +290 -0
- package/llm/components/select.llm.md +338 -0
- package/llm/components/separator.llm.md +129 -0
- package/llm/components/sheet.llm.md +275 -0
- package/llm/components/sidebar.llm.md +528 -0
- package/llm/components/skeleton.llm.md +140 -0
- package/llm/components/slider.llm.md +213 -0
- package/llm/components/sonner.llm.md +299 -0
- package/llm/components/spinner.llm.md +187 -0
- package/llm/components/switch.llm.md +258 -0
- package/llm/components/table.llm.md +334 -0
- package/llm/components/tabs.llm.md +245 -0
- package/llm/components/text.llm.md +108 -0
- package/llm/components/textarea.llm.md +236 -0
- package/llm/components/title.llm.md +88 -0
- package/llm/components/toggle-group.llm.md +228 -0
- package/llm/components/toggle.llm.md +235 -0
- package/llm/components/tooltip.llm.md +191 -0
- package/llm/contributing.llm.md +273 -0
- package/llm/hooks.llm.md +91 -0
- package/llm/index.llm.md +178 -0
- package/llm/theming.llm.md +381 -0
- package/llm/utilities.llm.md +97 -0
- package/llms-full.txt +15995 -0
- package/llms.txt +182 -0
- package/package.json +5 -1
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
# ContextMenu
|
|
2
|
+
|
|
3
|
+
Right-click context menu with support for nested submenus, checkboxes, radio groups, keyboard shortcuts, and destructive actions.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import {
|
|
9
|
+
ContextMenu,
|
|
10
|
+
ContextMenuTrigger,
|
|
11
|
+
ContextMenuContent,
|
|
12
|
+
ContextMenuItem,
|
|
13
|
+
ContextMenuCheckboxItem,
|
|
14
|
+
ContextMenuRadioItem,
|
|
15
|
+
ContextMenuRadioGroup,
|
|
16
|
+
ContextMenuLabel,
|
|
17
|
+
ContextMenuSeparator,
|
|
18
|
+
ContextMenuShortcut,
|
|
19
|
+
ContextMenuGroup,
|
|
20
|
+
ContextMenuSub,
|
|
21
|
+
ContextMenuSubTrigger,
|
|
22
|
+
ContextMenuSubContent,
|
|
23
|
+
} from "@neynar/ui/context-menu"
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Anatomy
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
<ContextMenu>
|
|
30
|
+
<ContextMenuTrigger>Right-click target</ContextMenuTrigger>
|
|
31
|
+
<ContextMenuContent>
|
|
32
|
+
<ContextMenuGroup>
|
|
33
|
+
<ContextMenuLabel>Section</ContextMenuLabel>
|
|
34
|
+
<ContextMenuItem>Action</ContextMenuItem>
|
|
35
|
+
<ContextMenuCheckboxItem>Toggle</ContextMenuCheckboxItem>
|
|
36
|
+
</ContextMenuGroup>
|
|
37
|
+
<ContextMenuSeparator />
|
|
38
|
+
<ContextMenuRadioGroup>
|
|
39
|
+
<ContextMenuRadioItem value="option">Option</ContextMenuRadioItem>
|
|
40
|
+
</ContextMenuRadioGroup>
|
|
41
|
+
<ContextMenuSub>
|
|
42
|
+
<ContextMenuSubTrigger>More</ContextMenuSubTrigger>
|
|
43
|
+
<ContextMenuSubContent>
|
|
44
|
+
<ContextMenuItem>Nested action</ContextMenuItem>
|
|
45
|
+
</ContextMenuSubContent>
|
|
46
|
+
</ContextMenuSub>
|
|
47
|
+
</ContextMenuContent>
|
|
48
|
+
</ContextMenu>
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Components
|
|
52
|
+
|
|
53
|
+
| Component | Description |
|
|
54
|
+
|-----------|-------------|
|
|
55
|
+
| ContextMenu | Root container, manages open/closed state |
|
|
56
|
+
| ContextMenuTrigger | Element that opens menu on right-click |
|
|
57
|
+
| ContextMenuContent | Menu popup with automatic portal and positioning |
|
|
58
|
+
| ContextMenuItem | Interactive menu action |
|
|
59
|
+
| ContextMenuCheckboxItem | Menu item with checkbox state |
|
|
60
|
+
| ContextMenuRadioItem | Menu item for mutually exclusive selection |
|
|
61
|
+
| ContextMenuRadioGroup | Container for radio items |
|
|
62
|
+
| ContextMenuLabel | Non-interactive section label |
|
|
63
|
+
| ContextMenuSeparator | Visual divider between items |
|
|
64
|
+
| ContextMenuShortcut | Keyboard shortcut hint (right-aligned) |
|
|
65
|
+
| ContextMenuGroup | Groups related items |
|
|
66
|
+
| ContextMenuSub | Root for nested submenu |
|
|
67
|
+
| ContextMenuSubTrigger | Item that opens submenu |
|
|
68
|
+
| ContextMenuSubContent | Submenu popup content |
|
|
69
|
+
|
|
70
|
+
## Props
|
|
71
|
+
|
|
72
|
+
### ContextMenu
|
|
73
|
+
|
|
74
|
+
| Prop | Type | Default | Description |
|
|
75
|
+
|------|------|---------|-------------|
|
|
76
|
+
| open | boolean | - | Controlled open state |
|
|
77
|
+
| onOpenChange | (open: boolean) => void | - | Called when open state changes |
|
|
78
|
+
| defaultOpen | boolean | false | Uncontrolled initial open state |
|
|
79
|
+
|
|
80
|
+
### ContextMenuContent
|
|
81
|
+
|
|
82
|
+
Automatically renders portal and positioner.
|
|
83
|
+
|
|
84
|
+
| Prop | Type | Default | Description |
|
|
85
|
+
|------|------|---------|-------------|
|
|
86
|
+
| align | "start" \| "end" \| "center" | "start" | Alignment relative to trigger |
|
|
87
|
+
| alignOffset | number | 4 | Offset from alignment edge (px) |
|
|
88
|
+
| side | "top" \| "right" \| "bottom" \| "left" | "right" | Which side to position menu |
|
|
89
|
+
| sideOffset | number | 0 | Offset from trigger (px) |
|
|
90
|
+
|
|
91
|
+
### ContextMenuItem
|
|
92
|
+
|
|
93
|
+
| Prop | Type | Default | Description |
|
|
94
|
+
|------|------|---------|-------------|
|
|
95
|
+
| variant | "default" \| "destructive" \| "success" \| "warning" \| "info" | "default" | Visual style variant |
|
|
96
|
+
| inset | boolean | false | Extra left padding for alignment |
|
|
97
|
+
| disabled | boolean | false | Disables interaction |
|
|
98
|
+
| closeOnClick | boolean | true | Close menu when clicked |
|
|
99
|
+
|
|
100
|
+
### ContextMenuCheckboxItem
|
|
101
|
+
|
|
102
|
+
| Prop | Type | Default | Description |
|
|
103
|
+
|------|------|---------|-------------|
|
|
104
|
+
| checked | boolean \| "indeterminate" | - | Controlled checked state |
|
|
105
|
+
| onCheckedChange | (checked: boolean) => void | - | Called when checked changes |
|
|
106
|
+
| disabled | boolean | false | Disables interaction |
|
|
107
|
+
|
|
108
|
+
### ContextMenuRadioGroup
|
|
109
|
+
|
|
110
|
+
| Prop | Type | Default | Description |
|
|
111
|
+
|------|------|---------|-------------|
|
|
112
|
+
| value | string | - | Controlled selected value |
|
|
113
|
+
| onValueChange | (value: string) => void | - | Called when selection changes |
|
|
114
|
+
|
|
115
|
+
### ContextMenuRadioItem
|
|
116
|
+
|
|
117
|
+
| Prop | Type | Default | Description |
|
|
118
|
+
|------|------|---------|-------------|
|
|
119
|
+
| value | string | - | Value for this radio option |
|
|
120
|
+
| disabled | boolean | false | Disables interaction |
|
|
121
|
+
|
|
122
|
+
### ContextMenuLabel
|
|
123
|
+
|
|
124
|
+
| Prop | Type | Default | Description |
|
|
125
|
+
|------|------|---------|-------------|
|
|
126
|
+
| inset | boolean | false | Extra left padding for alignment |
|
|
127
|
+
|
|
128
|
+
### ContextMenuSubTrigger
|
|
129
|
+
|
|
130
|
+
| Prop | Type | Default | Description |
|
|
131
|
+
|------|------|---------|-------------|
|
|
132
|
+
| inset | boolean | false | Extra left padding for alignment |
|
|
133
|
+
|
|
134
|
+
Automatically includes chevron icon.
|
|
135
|
+
|
|
136
|
+
## Data Attributes
|
|
137
|
+
|
|
138
|
+
| Attribute | When Present | Applied To |
|
|
139
|
+
|-----------|--------------|------------|
|
|
140
|
+
| data-open | Menu is open | ContextMenuContent |
|
|
141
|
+
| data-closed | Menu is closed | ContextMenuContent |
|
|
142
|
+
| data-highlighted | Item is keyboard-focused | ContextMenuItem, ContextMenuSubTrigger |
|
|
143
|
+
| data-disabled | Item is disabled | ContextMenuItem, ContextMenuCheckboxItem, ContextMenuRadioItem |
|
|
144
|
+
| data-inset | Inset prop is true | ContextMenuLabel, ContextMenuItem, ContextMenuSubTrigger |
|
|
145
|
+
| data-side | Position side | ContextMenuContent |
|
|
146
|
+
|
|
147
|
+
## Variants
|
|
148
|
+
|
|
149
|
+
ContextMenuItem supports semantic variants:
|
|
150
|
+
|
|
151
|
+
| Variant | Use Case |
|
|
152
|
+
|---------|----------|
|
|
153
|
+
| default | Standard actions |
|
|
154
|
+
| destructive | Delete, remove, irreversible actions |
|
|
155
|
+
| success | Approve, confirm actions |
|
|
156
|
+
| warning | Actions requiring caution |
|
|
157
|
+
| info | Informational actions |
|
|
158
|
+
|
|
159
|
+
## Examples
|
|
160
|
+
|
|
161
|
+
### Basic Context Menu
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
<ContextMenu>
|
|
165
|
+
<ContextMenuTrigger>
|
|
166
|
+
<div className="border p-4 rounded">Right-click here</div>
|
|
167
|
+
</ContextMenuTrigger>
|
|
168
|
+
<ContextMenuContent>
|
|
169
|
+
<ContextMenuItem>
|
|
170
|
+
<EditIcon />
|
|
171
|
+
Edit
|
|
172
|
+
</ContextMenuItem>
|
|
173
|
+
<ContextMenuItem>
|
|
174
|
+
<CopyIcon />
|
|
175
|
+
Copy
|
|
176
|
+
</ContextMenuItem>
|
|
177
|
+
<ContextMenuSeparator />
|
|
178
|
+
<ContextMenuItem variant="destructive">
|
|
179
|
+
<TrashIcon />
|
|
180
|
+
Delete
|
|
181
|
+
</ContextMenuItem>
|
|
182
|
+
</ContextMenuContent>
|
|
183
|
+
</ContextMenu>
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### With Keyboard Shortcuts
|
|
187
|
+
|
|
188
|
+
```tsx
|
|
189
|
+
<ContextMenuContent>
|
|
190
|
+
<ContextMenuItem>
|
|
191
|
+
<EditIcon />
|
|
192
|
+
Edit
|
|
193
|
+
<ContextMenuShortcut>⌘E</ContextMenuShortcut>
|
|
194
|
+
</ContextMenuItem>
|
|
195
|
+
<ContextMenuItem>
|
|
196
|
+
<CopyIcon />
|
|
197
|
+
Copy
|
|
198
|
+
<ContextMenuShortcut>⌘C</ContextMenuShortcut>
|
|
199
|
+
</ContextMenuItem>
|
|
200
|
+
</ContextMenuContent>
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Grouped Items with Labels
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
<ContextMenuContent>
|
|
207
|
+
<ContextMenuGroup>
|
|
208
|
+
<ContextMenuLabel>Actions</ContextMenuLabel>
|
|
209
|
+
<ContextMenuItem>Edit</ContextMenuItem>
|
|
210
|
+
<ContextMenuItem>Copy</ContextMenuItem>
|
|
211
|
+
</ContextMenuGroup>
|
|
212
|
+
<ContextMenuSeparator />
|
|
213
|
+
<ContextMenuGroup>
|
|
214
|
+
<ContextMenuLabel>Organization</ContextMenuLabel>
|
|
215
|
+
<ContextMenuItem>Add to Favorites</ContextMenuItem>
|
|
216
|
+
<ContextMenuItem>Pin</ContextMenuItem>
|
|
217
|
+
</ContextMenuGroup>
|
|
218
|
+
</ContextMenuContent>
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Checkbox Items
|
|
222
|
+
|
|
223
|
+
```tsx
|
|
224
|
+
function ViewOptions() {
|
|
225
|
+
const [showGrid, setShowGrid] = useState(true)
|
|
226
|
+
const [showLabels, setShowLabels] = useState(false)
|
|
227
|
+
|
|
228
|
+
return (
|
|
229
|
+
<ContextMenuContent>
|
|
230
|
+
<ContextMenuGroup>
|
|
231
|
+
<ContextMenuLabel>View Options</ContextMenuLabel>
|
|
232
|
+
</ContextMenuGroup>
|
|
233
|
+
<ContextMenuCheckboxItem
|
|
234
|
+
checked={showGrid}
|
|
235
|
+
onCheckedChange={setShowGrid}
|
|
236
|
+
>
|
|
237
|
+
Show Grid
|
|
238
|
+
</ContextMenuCheckboxItem>
|
|
239
|
+
<ContextMenuCheckboxItem
|
|
240
|
+
checked={showLabels}
|
|
241
|
+
onCheckedChange={setShowLabels}
|
|
242
|
+
>
|
|
243
|
+
Show Labels
|
|
244
|
+
</ContextMenuCheckboxItem>
|
|
245
|
+
</ContextMenuContent>
|
|
246
|
+
)
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### Radio Group
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
function SortMenu() {
|
|
254
|
+
const [sortBy, setSortBy] = useState("name")
|
|
255
|
+
|
|
256
|
+
return (
|
|
257
|
+
<ContextMenuContent>
|
|
258
|
+
<ContextMenuGroup>
|
|
259
|
+
<ContextMenuLabel>Sort By</ContextMenuLabel>
|
|
260
|
+
</ContextMenuGroup>
|
|
261
|
+
<ContextMenuRadioGroup value={sortBy} onValueChange={setSortBy}>
|
|
262
|
+
<ContextMenuRadioItem value="name">Name</ContextMenuRadioItem>
|
|
263
|
+
<ContextMenuRadioItem value="date">Date</ContextMenuRadioItem>
|
|
264
|
+
<ContextMenuRadioItem value="size">Size</ContextMenuRadioItem>
|
|
265
|
+
</ContextMenuRadioGroup>
|
|
266
|
+
</ContextMenuContent>
|
|
267
|
+
)
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
### Nested Submenus
|
|
272
|
+
|
|
273
|
+
```tsx
|
|
274
|
+
<ContextMenuContent>
|
|
275
|
+
<ContextMenuItem>Edit</ContextMenuItem>
|
|
276
|
+
<ContextMenuItem>Copy</ContextMenuItem>
|
|
277
|
+
<ContextMenuSeparator />
|
|
278
|
+
<ContextMenuSub>
|
|
279
|
+
<ContextMenuSubTrigger>
|
|
280
|
+
<ShareIcon />
|
|
281
|
+
Share
|
|
282
|
+
</ContextMenuSubTrigger>
|
|
283
|
+
<ContextMenuSubContent>
|
|
284
|
+
<ContextMenuItem>
|
|
285
|
+
<MailIcon />
|
|
286
|
+
Email
|
|
287
|
+
</ContextMenuItem>
|
|
288
|
+
<ContextMenuItem>
|
|
289
|
+
<CopyIcon />
|
|
290
|
+
Copy Link
|
|
291
|
+
</ContextMenuItem>
|
|
292
|
+
<ContextMenuItem>
|
|
293
|
+
<DownloadIcon />
|
|
294
|
+
Download
|
|
295
|
+
</ContextMenuItem>
|
|
296
|
+
</ContextMenuSubContent>
|
|
297
|
+
</ContextMenuSub>
|
|
298
|
+
</ContextMenuContent>
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Inset Alignment
|
|
302
|
+
|
|
303
|
+
Use `inset` prop to align items that don't have icons with items that do:
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
<ContextMenuContent>
|
|
307
|
+
<ContextMenuGroup>
|
|
308
|
+
<ContextMenuLabel>Navigation</ContextMenuLabel>
|
|
309
|
+
<ContextMenuItem>
|
|
310
|
+
<UserIcon />
|
|
311
|
+
Profile
|
|
312
|
+
</ContextMenuItem>
|
|
313
|
+
<ContextMenuItem inset>Account Settings</ContextMenuItem>
|
|
314
|
+
<ContextMenuItem inset>Privacy Settings</ContextMenuItem>
|
|
315
|
+
</ContextMenuGroup>
|
|
316
|
+
</ContextMenuContent>
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Variant Examples
|
|
320
|
+
|
|
321
|
+
```tsx
|
|
322
|
+
<ContextMenuContent>
|
|
323
|
+
<ContextMenuItem>Default Action</ContextMenuItem>
|
|
324
|
+
<ContextMenuSeparator />
|
|
325
|
+
<ContextMenuItem variant="success">
|
|
326
|
+
<CheckCircle2Icon />
|
|
327
|
+
Approve
|
|
328
|
+
</ContextMenuItem>
|
|
329
|
+
<ContextMenuItem variant="warning">
|
|
330
|
+
<AlertTriangleIcon />
|
|
331
|
+
Mark for Review
|
|
332
|
+
</ContextMenuItem>
|
|
333
|
+
<ContextMenuItem variant="info">
|
|
334
|
+
<InfoIcon />
|
|
335
|
+
View Details
|
|
336
|
+
</ContextMenuItem>
|
|
337
|
+
<ContextMenuSeparator />
|
|
338
|
+
<ContextMenuItem variant="destructive">
|
|
339
|
+
<TrashIcon />
|
|
340
|
+
Delete
|
|
341
|
+
</ContextMenuItem>
|
|
342
|
+
</ContextMenuContent>
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Keyboard
|
|
346
|
+
|
|
347
|
+
| Key | Action |
|
|
348
|
+
|-----|--------|
|
|
349
|
+
| Space / Enter | Activate focused item |
|
|
350
|
+
| ArrowDown | Move focus to next item |
|
|
351
|
+
| ArrowUp | Move focus to previous item |
|
|
352
|
+
| ArrowRight | Open submenu (when focused on SubTrigger) |
|
|
353
|
+
| ArrowLeft | Close submenu |
|
|
354
|
+
| Escape | Close menu |
|
|
355
|
+
| Tab | Move focus out and close |
|
|
356
|
+
|
|
357
|
+
## Accessibility
|
|
358
|
+
|
|
359
|
+
- Right-click or Shift+F10 opens context menu
|
|
360
|
+
- ARIA roles: `menu`, `menuitem`, `menuitemcheckbox`, `menuitemradio`
|
|
361
|
+
- Focus is trapped within open menu
|
|
362
|
+
- Screen readers announce menu state, selected items, and keyboard shortcuts
|
|
363
|
+
- CheckboxItem and RadioItem include proper ARIA checked states
|
|
364
|
+
|
|
365
|
+
## Related
|
|
366
|
+
|
|
367
|
+
- [DropdownMenu](./dropdown-menu.llm.md) - Click-triggered menu
|
|
368
|
+
- [Menubar](./menubar.llm.md) - Application menu bar
|
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
# Dialog
|
|
2
|
+
|
|
3
|
+
Modal overlay component for capturing user attention, gathering input, or confirming actions.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import {
|
|
9
|
+
Dialog,
|
|
10
|
+
DialogClose,
|
|
11
|
+
DialogContent,
|
|
12
|
+
DialogDescription,
|
|
13
|
+
DialogFooter,
|
|
14
|
+
DialogHeader,
|
|
15
|
+
DialogTitle,
|
|
16
|
+
DialogTrigger,
|
|
17
|
+
} from "@neynar/ui/dialog"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Anatomy
|
|
21
|
+
|
|
22
|
+
```tsx
|
|
23
|
+
<Dialog>
|
|
24
|
+
<DialogTrigger>Open</DialogTrigger>
|
|
25
|
+
<DialogContent>
|
|
26
|
+
<DialogHeader>
|
|
27
|
+
<DialogTitle>Title</DialogTitle>
|
|
28
|
+
<DialogDescription>Description</DialogDescription>
|
|
29
|
+
</DialogHeader>
|
|
30
|
+
{/* Content */}
|
|
31
|
+
<DialogFooter>
|
|
32
|
+
<DialogClose>Cancel</DialogClose>
|
|
33
|
+
</DialogFooter>
|
|
34
|
+
</DialogContent>
|
|
35
|
+
</Dialog>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Components
|
|
39
|
+
|
|
40
|
+
| Component | Description |
|
|
41
|
+
|-----------|-------------|
|
|
42
|
+
| Dialog | Root container that manages open state (controlled or uncontrolled) |
|
|
43
|
+
| DialogTrigger | Button that opens the dialog, supports `render` prop for customization |
|
|
44
|
+
| DialogContent | Main content container with automatic portal, overlay, and animations |
|
|
45
|
+
| DialogHeader | Container for title and description with consistent spacing |
|
|
46
|
+
| DialogTitle | Accessible heading element, required for screen readers |
|
|
47
|
+
| DialogDescription | Optional description text with support for inline links |
|
|
48
|
+
| DialogFooter | Action button container, stacks vertically on mobile |
|
|
49
|
+
| DialogClose | Button that closes the dialog, works with `render` prop |
|
|
50
|
+
| DialogOverlay | Backdrop overlay with blur effect (auto-included in DialogContent) |
|
|
51
|
+
| DialogPortal | Portal to document root (auto-included in DialogContent) |
|
|
52
|
+
|
|
53
|
+
## Props
|
|
54
|
+
|
|
55
|
+
### Dialog
|
|
56
|
+
|
|
57
|
+
| Prop | Type | Default | Description |
|
|
58
|
+
|------|------|---------|-------------|
|
|
59
|
+
| open | boolean | - | Controlled open state |
|
|
60
|
+
| onOpenChange | (open: boolean) => void | - | Callback when open state changes |
|
|
61
|
+
| defaultOpen | boolean | - | Initial open state (uncontrolled) |
|
|
62
|
+
|
|
63
|
+
### DialogContent
|
|
64
|
+
|
|
65
|
+
Automatically renders into a portal with overlay backdrop. Centered on screen with fade and zoom animations.
|
|
66
|
+
|
|
67
|
+
| Prop | Type | Default | Description |
|
|
68
|
+
|------|------|---------|-------------|
|
|
69
|
+
| showCloseButton | boolean | true | Show close button (X) in top-right corner |
|
|
70
|
+
| className | string | - | Additional CSS classes |
|
|
71
|
+
|
|
72
|
+
### DialogFooter
|
|
73
|
+
|
|
74
|
+
| Prop | Type | Default | Description |
|
|
75
|
+
|------|------|---------|-------------|
|
|
76
|
+
| showCloseButton | boolean | false | Render a "Close" button automatically |
|
|
77
|
+
| className | string | - | Additional CSS classes |
|
|
78
|
+
|
|
79
|
+
### Render Prop Pattern
|
|
80
|
+
|
|
81
|
+
DialogTrigger and DialogClose support the `render` prop to customize the underlying element:
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
<DialogTrigger render={<Button variant="destructive" />}>
|
|
85
|
+
Delete Account
|
|
86
|
+
</DialogTrigger>
|
|
87
|
+
|
|
88
|
+
<DialogClose render={<Button variant="outline" />}>
|
|
89
|
+
Cancel
|
|
90
|
+
</DialogClose>
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
This allows you to use any component while preserving dialog functionality.
|
|
94
|
+
|
|
95
|
+
## Data Attributes
|
|
96
|
+
|
|
97
|
+
Applied automatically for styling and animations:
|
|
98
|
+
|
|
99
|
+
| Attribute | When Present | Usage |
|
|
100
|
+
|-----------|--------------|-------|
|
|
101
|
+
| data-open | Dialog is open | Styling open state, animations |
|
|
102
|
+
| data-closed | Dialog is closed | Styling closed state, exit animations |
|
|
103
|
+
| data-slot | Always | Component identification ("dialog", "dialog-trigger", etc.) |
|
|
104
|
+
|
|
105
|
+
## Examples
|
|
106
|
+
|
|
107
|
+
### Basic Dialog
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
<Dialog>
|
|
111
|
+
<DialogTrigger render={<Button />}>Open Dialog</DialogTrigger>
|
|
112
|
+
<DialogContent>
|
|
113
|
+
<DialogHeader>
|
|
114
|
+
<DialogTitle>Dialog Title</DialogTitle>
|
|
115
|
+
<DialogDescription>
|
|
116
|
+
This is a description providing context about the dialog.
|
|
117
|
+
</DialogDescription>
|
|
118
|
+
</DialogHeader>
|
|
119
|
+
<DialogFooter>
|
|
120
|
+
<DialogClose render={<Button variant="outline" />}>Cancel</DialogClose>
|
|
121
|
+
<Button>Confirm</Button>
|
|
122
|
+
</DialogFooter>
|
|
123
|
+
</DialogContent>
|
|
124
|
+
</Dialog>
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Controlled State
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
function ControlledDialog() {
|
|
131
|
+
const [open, setOpen] = useState(false)
|
|
132
|
+
|
|
133
|
+
return (
|
|
134
|
+
<>
|
|
135
|
+
<Button onClick={() => setOpen(true)}>Open from Outside</Button>
|
|
136
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
137
|
+
<DialogTrigger render={<Button />}>Open Dialog</DialogTrigger>
|
|
138
|
+
<DialogContent>
|
|
139
|
+
<DialogHeader>
|
|
140
|
+
<DialogTitle>Controlled Dialog</DialogTitle>
|
|
141
|
+
<DialogDescription>
|
|
142
|
+
State is controlled by React state.
|
|
143
|
+
</DialogDescription>
|
|
144
|
+
</DialogHeader>
|
|
145
|
+
<DialogFooter>
|
|
146
|
+
<Button onClick={() => setOpen(false)}>Close Programmatically</Button>
|
|
147
|
+
</DialogFooter>
|
|
148
|
+
</DialogContent>
|
|
149
|
+
</Dialog>
|
|
150
|
+
</>
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Form Dialog
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
<Dialog>
|
|
159
|
+
<DialogTrigger render={<Button />}>
|
|
160
|
+
<PlusIcon data-icon="inline-start" />
|
|
161
|
+
Create Project
|
|
162
|
+
</DialogTrigger>
|
|
163
|
+
<DialogContent>
|
|
164
|
+
<DialogHeader>
|
|
165
|
+
<DialogTitle>Create New Project</DialogTitle>
|
|
166
|
+
<DialogDescription>
|
|
167
|
+
Set up a new project to organize your API keys.
|
|
168
|
+
</DialogDescription>
|
|
169
|
+
</DialogHeader>
|
|
170
|
+
<div className="space-y-4">
|
|
171
|
+
<div className="space-y-2">
|
|
172
|
+
<Label htmlFor="name">Project Name</Label>
|
|
173
|
+
<Input id="name" placeholder="My Awesome Project" />
|
|
174
|
+
</div>
|
|
175
|
+
<div className="space-y-2">
|
|
176
|
+
<Label htmlFor="description">Description</Label>
|
|
177
|
+
<Input id="description" placeholder="Brief description" />
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
<DialogFooter>
|
|
181
|
+
<DialogClose render={<Button variant="outline" />}>Cancel</DialogClose>
|
|
182
|
+
<Button>
|
|
183
|
+
<PlusIcon data-icon="inline-start" />
|
|
184
|
+
Create Project
|
|
185
|
+
</Button>
|
|
186
|
+
</DialogFooter>
|
|
187
|
+
</DialogContent>
|
|
188
|
+
</Dialog>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Destructive Confirmation
|
|
192
|
+
|
|
193
|
+
```tsx
|
|
194
|
+
function DeleteConfirmation() {
|
|
195
|
+
const [isDeleting, setIsDeleting] = useState(false)
|
|
196
|
+
|
|
197
|
+
function handleDelete() {
|
|
198
|
+
setIsDeleting(true)
|
|
199
|
+
// Perform delete operation
|
|
200
|
+
setTimeout(() => setIsDeleting(false), 1500)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
<Dialog>
|
|
205
|
+
<DialogTrigger render={<Button variant="destructive" />}>
|
|
206
|
+
<TrashIcon data-icon="inline-start" />
|
|
207
|
+
Revoke Key
|
|
208
|
+
</DialogTrigger>
|
|
209
|
+
<DialogContent>
|
|
210
|
+
<DialogHeader>
|
|
211
|
+
<DialogTitle>Revoke API Key?</DialogTitle>
|
|
212
|
+
<DialogDescription>
|
|
213
|
+
This action cannot be undone. Revoking this key will immediately
|
|
214
|
+
stop all applications using it from accessing the API.
|
|
215
|
+
</DialogDescription>
|
|
216
|
+
</DialogHeader>
|
|
217
|
+
<DialogFooter>
|
|
218
|
+
<DialogClose render={<Button variant="outline" />}>Cancel</DialogClose>
|
|
219
|
+
<Button variant="destructive" onClick={handleDelete} disabled={isDeleting}>
|
|
220
|
+
{isDeleting ? (
|
|
221
|
+
<>
|
|
222
|
+
<Loader2Icon data-icon="inline-start" className="animate-spin" />
|
|
223
|
+
Revoking...
|
|
224
|
+
</>
|
|
225
|
+
) : (
|
|
226
|
+
<>
|
|
227
|
+
<TrashIcon data-icon="inline-start" />
|
|
228
|
+
Revoke Key
|
|
229
|
+
</>
|
|
230
|
+
)}
|
|
231
|
+
</Button>
|
|
232
|
+
</DialogFooter>
|
|
233
|
+
</DialogContent>
|
|
234
|
+
</Dialog>
|
|
235
|
+
)
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Without Close Button
|
|
240
|
+
|
|
241
|
+
For dialogs that require explicit user action:
|
|
242
|
+
|
|
243
|
+
```tsx
|
|
244
|
+
<Dialog>
|
|
245
|
+
<DialogTrigger render={<Button />}>Forced Action</DialogTrigger>
|
|
246
|
+
<DialogContent showCloseButton={false}>
|
|
247
|
+
<DialogHeader>
|
|
248
|
+
<DialogTitle>Action Required</DialogTitle>
|
|
249
|
+
<DialogDescription>
|
|
250
|
+
Please choose one of the options below. This dialog cannot be
|
|
251
|
+
dismissed without making a selection.
|
|
252
|
+
</DialogDescription>
|
|
253
|
+
</DialogHeader>
|
|
254
|
+
<DialogFooter>
|
|
255
|
+
<DialogClose render={<Button variant="outline" />}>Option A</DialogClose>
|
|
256
|
+
<DialogClose render={<Button />}>Option B</DialogClose>
|
|
257
|
+
</DialogFooter>
|
|
258
|
+
</DialogContent>
|
|
259
|
+
</Dialog>
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Keyboard
|
|
263
|
+
|
|
264
|
+
| Key | Action |
|
|
265
|
+
|-----|--------|
|
|
266
|
+
| Escape | Closes the dialog (unless showCloseButton={false}) |
|
|
267
|
+
| Tab | Cycles through focusable elements within dialog |
|
|
268
|
+
|
|
269
|
+
## Accessibility
|
|
270
|
+
|
|
271
|
+
- Automatically sets `role="dialog"` and `aria-modal="true"`
|
|
272
|
+
- DialogTitle automatically provides `aria-labelledby` for the dialog
|
|
273
|
+
- DialogDescription provides `aria-describedby` when present
|
|
274
|
+
- Focus is trapped within the dialog when open
|
|
275
|
+
- Focus returns to trigger element when closed
|
|
276
|
+
- Escape key closes dialog by default
|
|
277
|
+
|
|
278
|
+
## Related
|
|
279
|
+
|
|
280
|
+
- **AlertDialog** - For simpler confirmations with pre-styled variants
|
|
281
|
+
- **Drawer** - For mobile-first slide-in panels
|
|
282
|
+
- **Popover** - For non-modal contextual overlays
|
|
283
|
+
- **Sheet** - For side-panel content
|