@neynar/ui 1.0.0 → 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.
Files changed (69) hide show
  1. package/README.md +1 -1
  2. package/context7.json +17 -0
  3. package/llm/components/accordion.llm.md +205 -0
  4. package/llm/components/alert-dialog.llm.md +289 -0
  5. package/llm/components/alert.llm.md +310 -0
  6. package/llm/components/aspect-ratio.llm.md +110 -0
  7. package/llm/components/avatar.llm.md +282 -0
  8. package/llm/components/badge.llm.md +185 -0
  9. package/llm/components/blockquote.llm.md +86 -0
  10. package/llm/components/breadcrumb.llm.md +245 -0
  11. package/llm/components/button-group.llm.md +248 -0
  12. package/llm/components/button.llm.md +247 -0
  13. package/llm/components/calendar.llm.md +252 -0
  14. package/llm/components/card.llm.md +356 -0
  15. package/llm/components/carousel.llm.md +281 -0
  16. package/llm/components/chart.llm.md +278 -0
  17. package/llm/components/checkbox.llm.md +234 -0
  18. package/llm/components/code.llm.md +75 -0
  19. package/llm/components/collapsible.llm.md +271 -0
  20. package/llm/components/color-mode.llm.md +196 -0
  21. package/llm/components/combobox.llm.md +346 -0
  22. package/llm/components/command.llm.md +353 -0
  23. package/llm/components/context-menu.llm.md +368 -0
  24. package/llm/components/dialog.llm.md +283 -0
  25. package/llm/components/drawer.llm.md +326 -0
  26. package/llm/components/dropdown-menu.llm.md +404 -0
  27. package/llm/components/empty.llm.md +282 -0
  28. package/llm/components/field.llm.md +303 -0
  29. package/llm/components/first-light.llm.md +129 -0
  30. package/llm/components/hover-card.llm.md +278 -0
  31. package/llm/components/input-group.llm.md +334 -0
  32. package/llm/components/input-otp.llm.md +270 -0
  33. package/llm/components/input.llm.md +197 -0
  34. package/llm/components/item.llm.md +347 -0
  35. package/llm/components/kbd.llm.md +221 -0
  36. package/llm/components/label.llm.md +219 -0
  37. package/llm/components/menubar.llm.md +378 -0
  38. package/llm/components/navigation-menu.llm.md +320 -0
  39. package/llm/components/pagination.llm.md +337 -0
  40. package/llm/components/popover.llm.md +278 -0
  41. package/llm/components/progress.llm.md +259 -0
  42. package/llm/components/radio-group.llm.md +269 -0
  43. package/llm/components/resizable.llm.md +222 -0
  44. package/llm/components/scroll-area.llm.md +290 -0
  45. package/llm/components/select.llm.md +338 -0
  46. package/llm/components/separator.llm.md +129 -0
  47. package/llm/components/sheet.llm.md +275 -0
  48. package/llm/components/sidebar.llm.md +528 -0
  49. package/llm/components/skeleton.llm.md +140 -0
  50. package/llm/components/slider.llm.md +213 -0
  51. package/llm/components/sonner.llm.md +299 -0
  52. package/llm/components/spinner.llm.md +187 -0
  53. package/llm/components/switch.llm.md +258 -0
  54. package/llm/components/table.llm.md +334 -0
  55. package/llm/components/tabs.llm.md +245 -0
  56. package/llm/components/text.llm.md +108 -0
  57. package/llm/components/textarea.llm.md +236 -0
  58. package/llm/components/title.llm.md +88 -0
  59. package/llm/components/toggle-group.llm.md +228 -0
  60. package/llm/components/toggle.llm.md +235 -0
  61. package/llm/components/tooltip.llm.md +191 -0
  62. package/llm/contributing.llm.md +273 -0
  63. package/llm/hooks.llm.md +91 -0
  64. package/llm/index.llm.md +178 -0
  65. package/llm/theming.llm.md +381 -0
  66. package/llm/utilities.llm.md +97 -0
  67. package/llms-full.txt +15995 -0
  68. package/llms.txt +182 -0
  69. package/package.json +6 -2
@@ -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