0
# Overlay Components
1
2
NextUI provides comprehensive overlay components for creating modal dialogs, popovers, dropdowns, and drawers with advanced positioning, animation, and interaction capabilities.
3
4
## Capabilities
5
6
### Modal
7
8
A flexible modal dialog component with customizable backdrop, scrolling behavior, and animations for displaying content above the main interface.
9
10
```typescript { .api }
11
interface ModalProps {
12
/** Modal content */
13
children: React.ReactNode;
14
/** Modal size */
15
size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "full";
16
/** Border radius */
17
radius?: "none" | "sm" | "md" | "lg";
18
/** Shadow intensity */
19
shadow?: "sm" | "md" | "lg";
20
/** Backdrop style */
21
backdrop?: "transparent" | "opaque" | "blur";
22
/** Scrolling behavior */
23
scrollBehavior?: "inside" | "outside";
24
/** Modal placement */
25
placement?: "auto" | "top" | "center" | "bottom";
26
/** Whether modal is open */
27
isOpen?: boolean;
28
/** Default open state */
29
defaultOpen?: boolean;
30
/** Whether modal can be dismissed */
31
isDismissable?: boolean;
32
/** Whether keyboard dismiss is disabled */
33
isKeyboardDismissDisabled?: boolean;
34
/** Hide close button */
35
hideCloseButton?: boolean;
36
/** Block scroll on body */
37
shouldBlockScroll?: boolean;
38
/** Portal container */
39
portalContainer?: Element;
40
/** Disable animations */
41
disableAnimation?: boolean;
42
/** Motion configuration */
43
motionProps?: MotionProps;
44
/** Custom CSS class */
45
className?: string;
46
/** Slot-based styling */
47
classNames?: SlotsToClasses<ModalSlots>;
48
/** Open change handler */
49
onOpenChange?: (isOpen: boolean) => void;
50
/** Close handler */
51
onClose?: () => void;
52
}
53
54
type ModalSlots =
55
| "wrapper" | "backdrop" | "base" | "header" | "body"
56
| "footer" | "closeButton";
57
58
function Modal(props: ModalProps): JSX.Element;
59
60
/**
61
* Hook for Modal state management
62
*/
63
function useModal(props: ModalProps): {
64
Component: React.ElementType;
65
slots: Record<ModalSlots, string>;
66
classNames: SlotsToClasses<ModalSlots>;
67
isOpen: boolean;
68
onClose: () => void;
69
getModalProps: () => any;
70
getBackdropProps: () => any;
71
getDialogProps: () => any;
72
};
73
```
74
75
### Modal Structure Components
76
77
Components for organizing modal content with proper accessibility and styling.
78
79
```typescript { .api }
80
interface ModalContentProps {
81
/** Modal content sections */
82
children?: React.ReactNode;
83
/** Custom CSS class */
84
className?: string;
85
}
86
87
interface ModalHeaderProps {
88
/** Header content */
89
children?: React.ReactNode;
90
/** Custom CSS class */
91
className?: string;
92
}
93
94
interface ModalBodyProps {
95
/** Body content */
96
children?: React.ReactNode;
97
/** Custom CSS class */
98
className?: string;
99
}
100
101
interface ModalFooterProps {
102
/** Footer content */
103
children?: React.ReactNode;
104
/** Custom CSS class */
105
className?: string;
106
}
107
108
function ModalContent(props: ModalContentProps): JSX.Element;
109
function ModalHeader(props: ModalHeaderProps): JSX.Element;
110
function ModalBody(props: ModalBodyProps): JSX.Element;
111
function ModalFooter(props: ModalFooterProps): JSX.Element;
112
```
113
114
**Modal Usage Example:**
115
116
```typescript
117
import {
118
Modal, ModalContent, ModalHeader, ModalBody, ModalFooter,
119
Button, Input, Checkbox, Link
120
} from "@nextui-org/react";
121
import { useDisclosure } from "@nextui-org/react";
122
123
function ModalExample() {
124
const { isOpen, onOpen, onOpenChange } = useDisclosure();
125
126
return (
127
<>
128
<Button onPress={onOpen} color="primary">
129
Open Modal
130
</Button>
131
<Modal
132
isOpen={isOpen}
133
onOpenChange={onOpenChange}
134
placement="top-center"
135
backdrop="blur"
136
>
137
<ModalContent>
138
{(onClose) => (
139
<>
140
<ModalHeader className="flex flex-col gap-1">
141
Log in
142
</ModalHeader>
143
<ModalBody>
144
<Input
145
autoFocus
146
label="Email"
147
placeholder="Enter your email"
148
variant="bordered"
149
/>
150
<Input
151
label="Password"
152
placeholder="Enter your password"
153
type="password"
154
variant="bordered"
155
/>
156
<div className="flex py-2 px-1 justify-between">
157
<Checkbox
158
classNames={{
159
label: "text-small",
160
}}
161
>
162
Remember me
163
</Checkbox>
164
<Link color="primary" href="#" size="sm">
165
Forgot password?
166
</Link>
167
</div>
168
</ModalBody>
169
<ModalFooter>
170
<Button color="danger" variant="flat" onPress={onClose}>
171
Close
172
</Button>
173
<Button color="primary" onPress={onClose}>
174
Sign in
175
</Button>
176
</ModalFooter>
177
</>
178
)}
179
</ModalContent>
180
</Modal>
181
</>
182
);
183
}
184
```
185
186
### Modal Context
187
188
Context system for sharing modal state across modal components.
189
190
```typescript { .api }
191
interface ModalProviderProps {
192
children: React.ReactNode;
193
value: ModalContextValue;
194
}
195
196
interface ModalContextValue {
197
slots: Record<ModalSlots, string>;
198
classNames?: SlotsToClasses<ModalSlots>;
199
isOpen?: boolean;
200
backdrop?: string;
201
hideCloseButton?: boolean;
202
motionProps?: MotionProps;
203
onClose?: () => void;
204
}
205
206
const ModalProvider: React.FC<ModalProviderProps>;
207
208
/**
209
* Hook to access modal context
210
* @throws Error if used outside ModalProvider
211
*/
212
function useModalContext(): ModalContextValue;
213
```
214
215
### Popover
216
217
A floating content container that appears relative to a trigger element with flexible positioning and content options.
218
219
```typescript { .api }
220
interface PopoverProps {
221
/** Popover content including trigger and content */
222
children: React.ReactNode;
223
/** Popover size */
224
size?: "sm" | "md" | "lg";
225
/** Color theme */
226
color?: "default" | "foreground" | "primary" | "secondary" | "success" | "warning" | "danger";
227
/** Border radius */
228
radius?: "none" | "sm" | "md" | "lg" | "full";
229
/** Shadow intensity */
230
shadow?: "sm" | "md" | "lg";
231
/** Backdrop style */
232
backdrop?: "transparent" | "opaque" | "blur";
233
/** Popover placement */
234
placement?: Placement;
235
/** Whether popover is open */
236
isOpen?: boolean;
237
/** Default open state */
238
defaultOpen?: boolean;
239
/** Whether popover should flip to fit */
240
shouldFlip?: boolean;
241
/** Whether to update position on scroll */
242
shouldUpdatePosition?: boolean;
243
/** Block scroll on body */
244
shouldBlockScroll?: boolean;
245
/** Whether popover can be dismissed */
246
isDismissable?: boolean;
247
/** Whether to close on blur */
248
shouldCloseOnBlur?: boolean;
249
/** Custom interact outside handler */
250
shouldCloseOnInteractOutside?: (element: Element) => boolean;
251
/** Whether keyboard dismiss is disabled */
252
isKeyboardDismissDisabled?: boolean;
253
/** Show arrow pointer */
254
showArrow?: boolean;
255
/** Offset from target */
256
offset?: number;
257
/** Cross-axis offset */
258
crossOffset?: number;
259
/** Container padding for flip calculations */
260
containerPadding?: number;
261
/** Trigger element ref */
262
triggerRef?: React.RefObject<Element>;
263
/** Scroll container ref */
264
scrollRef?: React.RefObject<Element>;
265
/** Portal container */
266
portalContainer?: Element;
267
/** Disable animations */
268
disableAnimation?: boolean;
269
/** Motion configuration */
270
motionProps?: MotionProps;
271
/** Custom CSS class */
272
className?: string;
273
/** Slot-based styling */
274
classNames?: SlotsToClasses<PopoverSlots>;
275
/** Open change handler */
276
onOpenChange?: (isOpen: boolean) => void;
277
}
278
279
type PopoverSlots = "base" | "trigger" | "backdrop" | "arrow" | "content";
280
281
function Popover(props: PopoverProps): JSX.Element;
282
283
/**
284
* Hook for Popover state management
285
*/
286
function usePopover(props: PopoverProps): {
287
Component: React.ElementType;
288
state: OverlayTriggerState;
289
slots: Record<PopoverSlots, string>;
290
classNames: SlotsToClasses<PopoverSlots>;
291
isOpen: boolean;
292
getPopoverProps: () => any;
293
getTriggerProps: () => any;
294
getContentProps: () => any;
295
};
296
```
297
298
### Popover Structure Components
299
300
Components for organizing popover content and trigger elements.
301
302
```typescript { .api }
303
interface PopoverTriggerProps {
304
/** Trigger element */
305
children: React.ReactElement;
306
}
307
308
interface PopoverContentProps {
309
/** Popover content */
310
children?: React.ReactNode;
311
/** Custom CSS class */
312
className?: string;
313
}
314
315
function PopoverTrigger(props: PopoverTriggerProps): JSX.Element;
316
function PopoverContent(props: PopoverContentProps): JSX.Element;
317
```
318
319
**Popover Usage Examples:**
320
321
```typescript
322
import {
323
Popover, PopoverTrigger, PopoverContent,
324
Button, Input, Card, CardBody, CardHeader
325
} from "@nextui-org/react";
326
327
function PopoverExamples() {
328
return (
329
<div className="space-y-4">
330
{/* Basic popover */}
331
<Popover placement="bottom" showArrow={true}>
332
<PopoverTrigger>
333
<Button>Open Popover</Button>
334
</PopoverTrigger>
335
<PopoverContent>
336
<div className="px-1 py-2">
337
<div className="text-small font-bold">Popover Content</div>
338
<div className="text-tiny">This is the popover content</div>
339
</div>
340
</PopoverContent>
341
</Popover>
342
343
{/* Form in popover */}
344
<Popover placement="bottom" backdrop="blur">
345
<PopoverTrigger>
346
<Button color="primary">Quick Action</Button>
347
</PopoverTrigger>
348
<PopoverContent className="w-[240px]">
349
{(titleProps) => (
350
<div className="px-1 py-2 w-full">
351
<p className="text-small font-bold text-foreground" {...titleProps}>
352
Quick Settings
353
</p>
354
<div className="mt-2 flex flex-col gap-2 w-full">
355
<Input label="Name" size="sm" variant="bordered" />
356
<Input label="Email" size="sm" variant="bordered" />
357
<Button size="sm" color="primary">
358
Save
359
</Button>
360
</div>
361
</div>
362
)}
363
</PopoverContent>
364
</Popover>
365
366
{/* Card in popover */}
367
<Popover>
368
<PopoverTrigger>
369
<Button variant="bordered">Show Details</Button>
370
</PopoverTrigger>
371
<PopoverContent className="p-0">
372
<Card shadow="none" className="max-w-[300px] border-none bg-transparent">
373
<CardHeader className="pb-0 pt-2 px-4 flex-col items-start">
374
<p className="text-tiny uppercase font-bold">Daily Mix</p>
375
<small className="text-default-500">12 Tracks</small>
376
<h4 className="font-bold text-large">Frontend Radio</h4>
377
</CardHeader>
378
<CardBody className="overflow-visible py-2">
379
<p className="text-small text-default-500">
380
The latest tracks from your favorite artists.
381
</p>
382
</CardBody>
383
</Card>
384
</PopoverContent>
385
</Popover>
386
</div>
387
);
388
}
389
```
390
391
### Free Solo Popover
392
393
A standalone popover component that doesn't require a trigger wrapper.
394
395
```typescript { .api }
396
interface FreeSoloPopoverProps {
397
/** Popover content */
398
children: React.ReactNode;
399
/** Target element to position relative to */
400
triggerRef: React.RefObject<Element>;
401
/** Whether popover is open */
402
isOpen?: boolean;
403
/** Popover placement */
404
placement?: Placement;
405
/** Show arrow pointer */
406
showArrow?: boolean;
407
/** Offset from target */
408
offset?: number;
409
/** Custom CSS class */
410
className?: string;
411
/** Slot-based styling */
412
classNames?: SlotsToClasses<PopoverSlots>;
413
/** Open change handler */
414
onOpenChange?: (isOpen: boolean) => void;
415
}
416
417
function FreeSoloPopover(props: FreeSoloPopoverProps): JSX.Element;
418
```
419
420
### Popover Context
421
422
Context system for sharing popover state across popover components.
423
424
```typescript { .api }
425
interface PopoverProviderProps {
426
children: React.ReactNode;
427
value: PopoverContextValue;
428
}
429
430
interface PopoverContextValue {
431
state: OverlayTriggerState;
432
slots: Record<PopoverSlots, string>;
433
classNames?: SlotsToClasses<PopoverSlots>;
434
showArrow?: boolean;
435
backdrop?: string;
436
motionProps?: MotionProps;
437
}
438
439
const PopoverProvider: React.FC<PopoverProviderProps>;
440
441
/**
442
* Hook to access popover context
443
* @throws Error if used outside PopoverProvider
444
*/
445
function usePopoverContext(): PopoverContextValue;
446
```
447
448
### Dropdown
449
450
A composite component combining popover functionality with menu items for creating dropdown menus.
451
452
```typescript { .api }
453
interface DropdownProps {
454
/** Dropdown content including trigger and menu */
455
children: React.ReactNode;
456
/** Dropdown type */
457
type?: "menu" | "listbox";
458
/** Trigger action */
459
trigger?: "press" | "longPress";
460
/** Whether dropdown is disabled */
461
isDisabled?: boolean;
462
/** Close on select */
463
closeOnSelect?: boolean;
464
/** Whether dropdown should flip to fit */
465
shouldFlip?: boolean;
466
/** Block scroll on body */
467
shouldBlockScroll?: boolean;
468
/** Show arrow pointer */
469
showArrow?: boolean;
470
/** Portal container */
471
portalContainer?: Element;
472
/** Disable animations */
473
disableAnimation?: boolean;
474
/** Custom CSS class */
475
className?: string;
476
/** Slot-based styling */
477
classNames?: SlotsToClasses<DropdownSlots>;
478
}
479
480
type DropdownSlots = "base" | "trigger" | "backdrop" | "arrow" | "content";
481
482
function Dropdown(props: DropdownProps): JSX.Element;
483
484
/**
485
* Hook for Dropdown state management
486
*/
487
function useDropdown(props: DropdownProps): {
488
Component: React.ElementType;
489
state: MenuTriggerState;
490
slots: Record<DropdownSlots, string>;
491
classNames: SlotsToClasses<DropdownSlots>;
492
getDropdownProps: () => any;
493
};
494
```
495
496
### Dropdown Structure Components
497
498
Components for organizing dropdown content with trigger and menu items.
499
500
```typescript { .api }
501
interface DropdownTriggerProps {
502
/** Trigger element */
503
children: React.ReactElement;
504
}
505
506
interface DropdownMenuProps {
507
/** Menu items */
508
children?: React.ReactNode;
509
/** Menu variant */
510
variant?: "solid" | "bordered" | "light" | "flat" | "faded" | "shadow";
511
/** Menu color theme */
512
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
513
/** Selection mode */
514
selectionMode?: "none" | "single" | "multiple";
515
/** Currently selected keys */
516
selectedKeys?: Selection;
517
/** Default selected keys */
518
defaultSelectedKeys?: Selection;
519
/** Prevent empty selection */
520
disallowEmptySelection?: boolean;
521
/** Close on select */
522
closeOnSelect?: boolean;
523
/** Custom CSS class */
524
className?: string;
525
/** Slot-based styling */
526
classNames?: SlotsToClasses<MenuSlots>;
527
/** Selection change handler */
528
onSelectionChange?: (keys: Selection) => void;
529
/** Action handler */
530
onAction?: (key: React.Key) => void;
531
/** Close handler */
532
onClose?: () => void;
533
}
534
535
// DropdownItem and DropdownSection are aliases for MenuItem and MenuSection
536
interface DropdownItemProps {
537
/** Item key identifier */
538
key?: React.Key;
539
/** Item content */
540
children?: React.ReactNode;
541
/** Item text value */
542
textValue?: string;
543
/** Item description */
544
description?: React.ReactNode;
545
/** Item shortcut */
546
shortcut?: React.ReactNode;
547
/** Start content (icon, etc.) */
548
startContent?: React.ReactNode;
549
/** End content (icon, badge, etc.) */
550
endContent?: React.ReactNode;
551
/** Whether item is disabled */
552
isDisabled?: boolean;
553
/** Whether to show divider after item */
554
showDivider?: boolean;
555
/** Custom CSS class */
556
className?: string;
557
/** Slot-based styling */
558
classNames?: SlotsToClasses<MenuItemSlots>;
559
}
560
561
interface DropdownSectionProps {
562
/** Section title */
563
title?: React.ReactNode;
564
/** Section items */
565
children?: React.ReactNode;
566
/** Whether to hide divider */
567
hideDivider?: boolean;
568
/** Whether to show divider */
569
showDivider?: boolean;
570
/** Custom CSS class */
571
className?: string;
572
/** Slot-based styling */
573
classNames?: SlotsToClasses<MenuSectionSlots>;
574
}
575
576
function DropdownTrigger(props: DropdownTriggerProps): JSX.Element;
577
function DropdownMenu(props: DropdownMenuProps): JSX.Element;
578
const DropdownItem: React.FC<DropdownItemProps>;
579
const DropdownSection: React.FC<DropdownSectionProps>;
580
```
581
582
**Dropdown Usage Examples:**
583
584
```typescript
585
import {
586
Dropdown, DropdownTrigger, DropdownMenu, DropdownItem, DropdownSection,
587
Button, Avatar, User
588
} from "@nextui-org/react";
589
import { PlusIcon, CopyIcon, EditIcon, DeleteIcon } from "@heroicons/react/24/solid";
590
591
function DropdownExamples() {
592
return (
593
<div className="flex gap-4">
594
{/* Basic dropdown */}
595
<Dropdown>
596
<DropdownTrigger>
597
<Button variant="bordered">Actions</Button>
598
</DropdownTrigger>
599
<DropdownMenu aria-label="Static Actions">
600
<DropdownItem key="new">New file</DropdownItem>
601
<DropdownItem key="copy">Copy link</DropdownItem>
602
<DropdownItem key="edit">Edit file</DropdownItem>
603
<DropdownItem key="delete" className="text-danger" color="danger">
604
Delete file
605
</DropdownItem>
606
</DropdownMenu>
607
</Dropdown>
608
609
{/* Dropdown with icons */}
610
<Dropdown>
611
<DropdownTrigger>
612
<Button isIconOnly variant="light">
613
<PlusIcon className="w-4 h-4" />
614
</Button>
615
</DropdownTrigger>
616
<DropdownMenu variant="faded" aria-label="Dropdown menu with icons">
617
<DropdownItem
618
key="new"
619
shortcut="⌘N"
620
startContent={<PlusIcon className="w-4 h-4" />}
621
>
622
New File
623
</DropdownItem>
624
<DropdownItem
625
key="copy"
626
shortcut="⌘C"
627
startContent={<CopyIcon className="w-4 h-4" />}
628
>
629
Copy Link
630
</DropdownItem>
631
<DropdownItem
632
key="edit"
633
shortcut="⌘⇧E"
634
startContent={<EditIcon className="w-4 h-4" />}
635
>
636
Edit File
637
</DropdownItem>
638
<DropdownItem
639
key="delete"
640
className="text-danger"
641
color="danger"
642
shortcut="⌘⇧D"
643
startContent={<DeleteIcon className="w-4 h-4" />}
644
>
645
Delete File
646
</DropdownItem>
647
</DropdownMenu>
648
</Dropdown>
649
650
{/* User dropdown with sections */}
651
<Dropdown placement="bottom-start">
652
<DropdownTrigger>
653
<User
654
as="button"
655
avatarProps={{
656
isBordered: true,
657
src: "https://i.pravatar.cc/150?u=a042581f4e29026024d",
658
}}
659
className="transition-transform"
660
description="@tonyreichert"
661
name="Tony Reichert"
662
/>
663
</DropdownTrigger>
664
<DropdownMenu aria-label="User Actions" variant="flat">
665
<DropdownItem key="profile" className="h-14 gap-2">
666
<p className="font-bold">Signed in as</p>
667
<p className="font-bold">@tonyreichert</p>
668
</DropdownItem>
669
<DropdownItem key="settings">My Settings</DropdownItem>
670
<DropdownItem key="team_settings">Team Settings</DropdownItem>
671
<DropdownItem key="analytics">Analytics</DropdownItem>
672
<DropdownItem key="system">System</DropdownItem>
673
<DropdownItem key="configurations">Configurations</DropdownItem>
674
<DropdownItem key="help_and_feedback">Help & Feedback</DropdownItem>
675
<DropdownItem key="logout" color="danger">
676
Log Out
677
</DropdownItem>
678
</DropdownMenu>
679
</Dropdown>
680
</div>
681
);
682
}
683
```
684
685
### Drawer
686
687
A slide-out panel component that extends modal functionality for creating side navigation and content panels.
688
689
```typescript { .api }
690
interface DrawerProps extends Omit<ModalProps, 'placement' | 'size'> {
691
/** Drawer placement */
692
placement?: "top" | "bottom" | "left" | "right";
693
/** Drawer size */
694
size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "full";
695
/** Hide overlay backdrop */
696
hideOverlay?: boolean;
697
}
698
699
function Drawer(props: DrawerProps): JSX.Element;
700
701
/**
702
* Hook for Drawer state management
703
*/
704
function useDrawer(props: DrawerProps): {
705
Component: React.ElementType;
706
slots: Record<ModalSlots, string>;
707
classNames: SlotsToClasses<ModalSlots>;
708
isOpen: boolean;
709
onClose: () => void;
710
getDrawerProps: () => any;
711
};
712
713
// Drawer structure components are aliases for Modal components
714
const DrawerContent: React.FC<ModalContentProps>;
715
const DrawerHeader: React.FC<ModalHeaderProps>;
716
const DrawerBody: React.FC<ModalBodyProps>;
717
const DrawerFooter: React.FC<ModalFooterProps>;
718
```
719
720
**Drawer Usage Example:**
721
722
```typescript
723
import {
724
Drawer, DrawerContent, DrawerHeader, DrawerBody, DrawerFooter,
725
Button, Link, Listbox, ListboxItem
726
} from "@nextui-org/react";
727
import { useDisclosure } from "@nextui-org/react";
728
729
function DrawerExample() {
730
const { isOpen, onOpen, onOpenChange } = useDisclosure();
731
732
const menuItems = [
733
{ key: "dashboard", label: "Dashboard" },
734
{ key: "projects", label: "Projects" },
735
{ key: "team", label: "Team" },
736
{ key: "settings", label: "Settings" },
737
];
738
739
return (
740
<>
741
<Button onPress={onOpen}>Open Drawer</Button>
742
<Drawer
743
isOpen={isOpen}
744
onOpenChange={onOpenChange}
745
placement="left"
746
size="md"
747
>
748
<DrawerContent>
749
{(onClose) => (
750
<>
751
<DrawerHeader className="flex flex-col gap-1">
752
Navigation
753
</DrawerHeader>
754
<DrawerBody>
755
<Listbox
756
aria-label="Navigation menu"
757
onAction={(key) => {
758
console.log(`Navigate to ${key}`);
759
onClose();
760
}}
761
>
762
{menuItems.map((item) => (
763
<ListboxItem key={item.key}>
764
{item.label}
765
</ListboxItem>
766
))}
767
</Listbox>
768
</DrawerBody>
769
<DrawerFooter>
770
<Button color="danger" variant="light" onPress={onClose}>
771
Close
772
</Button>
773
<Link href="/settings" onClick={onClose}>
774
Settings
775
</Link>
776
</DrawerFooter>
777
</>
778
)}
779
</DrawerContent>
780
</Drawer>
781
</>
782
);
783
}
784
```
785
786
## Overlay Component Types
787
788
```typescript { .api }
789
// Common overlay types
790
type OverlaySize = "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | "full";
791
type OverlayRadius = "none" | "sm" | "md" | "lg";
792
type OverlayColor = "default" | "foreground" | "primary" | "secondary" | "success" | "warning" | "danger";
793
type BackdropType = "transparent" | "opaque" | "blur";
794
795
// Placement for popovers and dropdowns
796
type PlacementAxis = "top" | "bottom" | "left" | "right";
797
type PlacementAlign = "start" | "end";
798
type Placement = PlacementAxis | `${PlacementAxis}-${PlacementAlign}`;
799
800
// Modal types
801
interface ModalState {
802
isOpen: boolean;
803
size: OverlaySize;
804
placement: "auto" | "top" | "center" | "bottom";
805
backdrop: BackdropType;
806
scrollBehavior: "inside" | "outside";
807
isDismissable: boolean;
808
}
809
810
// Popover types
811
interface PopoverState {
812
isOpen: boolean;
813
placement: Placement;
814
showArrow: boolean;
815
backdrop?: BackdropType;
816
shouldFlip: boolean;
817
isDismissable: boolean;
818
}
819
820
// Dropdown types
821
interface DropdownState extends PopoverState {
822
selectionMode: "none" | "single" | "multiple";
823
selectedKeys: Selection;
824
closeOnSelect: boolean;
825
}
826
827
// Overlay trigger states
828
interface OverlayTriggerState {
829
readonly isOpen: boolean;
830
setOpen(isOpen: boolean): void;
831
open(): void;
832
close(): void;
833
toggle(): void;
834
}
835
836
interface MenuTriggerState extends OverlayTriggerState {
837
focusStrategy?: FocusStrategy | null;
838
}
839
840
// Motion configuration for overlay animations
841
interface MotionProps {
842
initial?: any;
843
animate?: any;
844
exit?: any;
845
transition?: any;
846
variants?: any;
847
whileHover?: any;
848
whileTap?: any;
849
whileFocus?: any;
850
whileInView?: any;
851
}
852
853
// Focus management
854
type FocusStrategy = "first" | "last";
855
856
// Selection types for dropdowns
857
type Selection = "all" | Set<React.Key>;
858
```
859
860
## Integration Examples
861
862
### Disclosure Hook Usage
863
864
The `useDisclosure` hook provides a convenient way to manage open/closed state for overlay components.
865
866
```typescript { .api }
867
interface UseDisclosureProps {
868
/** Whether overlay is open */
869
isOpen?: boolean;
870
/** Default open state */
871
defaultOpen?: boolean;
872
/** Close handler */
873
onClose?: () => void;
874
/** Open change handler */
875
onOpenChange?: (isOpen: boolean) => void;
876
/** Disclosure ID */
877
id?: string;
878
}
879
880
interface UseDisclosureReturn {
881
/** Whether overlay is open */
882
isOpen: boolean;
883
/** Open the overlay */
884
onOpen: () => void;
885
/** Close the overlay */
886
onClose: () => void;
887
/** Toggle overlay state */
888
onOpenChange: (isOpen: boolean) => void;
889
/** Whether state is controlled */
890
isControlled: boolean;
891
/** Props for trigger button */
892
getButtonProps: (props?: any) => any;
893
/** Props for disclosure content */
894
getDisclosureProps: (props?: any) => any;
895
}
896
897
function useDisclosure(props?: UseDisclosureProps): UseDisclosureReturn;
898
```
899
900
### Draggable Modal
901
902
Advanced modal functionality with drag support.
903
904
```typescript { .api }
905
interface UseDraggableProps {
906
/** Whether dragging is disabled */
907
isDisabled?: boolean;
908
/** Target element ref */
909
targetRef?: React.RefObject<HTMLElement>;
910
/** Body element ref */
911
bodyRef?: React.RefObject<HTMLElement>;
912
/** Drag constraints */
913
dragConstraints?: any;
914
/** Drag elastic behavior */
915
dragElastic?: boolean;
916
}
917
918
interface UseDraggableReturn {
919
/** Motion props for draggable element */
920
dragProps: any;
921
/** Drag controls */
922
dragControls: any;
923
}
924
925
function useDraggable(props: UseDraggableProps): UseDraggableReturn;
926
```
927
928
### Complex Overlay Composition
929
930
```typescript
931
import {
932
Modal, ModalContent, ModalHeader, ModalBody, ModalFooter,
933
Popover, PopoverTrigger, PopoverContent,
934
Dropdown, DropdownTrigger, DropdownMenu, DropdownItem,
935
Button, Input, useDisclosure
936
} from "@nextui-org/react";
937
938
function ComplexOverlayExample() {
939
const modal = useDisclosure();
940
const [selectedAction, setSelectedAction] = useState<string>("");
941
942
return (
943
<div className="space-y-4">
944
{/* Main trigger */}
945
<Button onPress={modal.onOpen} color="primary">
946
Open Complex Dialog
947
</Button>
948
949
{/* Modal with nested overlays */}
950
<Modal
951
isOpen={modal.isOpen}
952
onOpenChange={modal.onOpenChange}
953
size="lg"
954
>
955
<ModalContent>
956
{(onClose) => (
957
<>
958
<ModalHeader>Project Settings</ModalHeader>
959
<ModalBody className="space-y-4">
960
<Input label="Project Name" placeholder="Enter project name" />
961
962
<div className="flex gap-2">
963
{/* Popover for additional info */}
964
<Popover>
965
<PopoverTrigger>
966
<Button variant="bordered" size="sm">
967
Help
968
</Button>
969
</PopoverTrigger>
970
<PopoverContent>
971
<div className="p-2 max-w-[200px]">
972
<p className="text-sm">
973
Choose a descriptive name for your project that will help you identify it later.
974
</p>
975
</div>
976
</PopoverContent>
977
</Popover>
978
979
{/* Dropdown for actions */}
980
<Dropdown>
981
<DropdownTrigger>
982
<Button variant="bordered" size="sm">
983
Actions
984
</Button>
985
</DropdownTrigger>
986
<DropdownMenu
987
onAction={(key) => setSelectedAction(key as string)}
988
>
989
<DropdownItem key="duplicate">Duplicate</DropdownItem>
990
<DropdownItem key="export">Export</DropdownItem>
991
<DropdownItem key="archive">Archive</DropdownItem>
992
<DropdownItem key="delete" color="danger">
993
Delete
994
</DropdownItem>
995
</DropdownMenu>
996
</Dropdown>
997
</div>
998
999
{selectedAction && (
1000
<div className="p-2 bg-default-100 rounded">
1001
Selected action: {selectedAction}
1002
</div>
1003
)}
1004
</ModalBody>
1005
<ModalFooter>
1006
<Button color="danger" variant="flat" onPress={onClose}>
1007
Cancel
1008
</Button>
1009
<Button color="primary" onPress={onClose}>
1010
Save Changes
1011
</Button>
1012
</ModalFooter>
1013
</>
1014
)}
1015
</ModalContent>
1016
</Modal>
1017
</div>
1018
);
1019
}
1020
```