Modal systems, tooltips, popovers, and overlay components for interactive content, contextual information, and user confirmations.
Full-featured modal system with various sizes, types, and interaction patterns.
/**
* Basic modal component
*/
interface ModalProps {
/** Modal is open */
open: boolean;
/** Close request handler */
onRequestClose?: (event: React.MouseEvent | React.KeyboardEvent) => void;
/** Modal heading text */
modalHeading?: string;
/** Modal label text */
modalLabel?: string;
/** Primary button text */
primaryButtonText?: string;
/** Secondary button text */
secondaryButtonText?: string;
/** Primary button click handler */
onRequestSubmit?: (event: React.MouseEvent<HTMLButtonElement>) => void;
/** Secondary button click handler */
onSecondarySubmit?: (event: React.MouseEvent<HTMLButtonElement>) => void;
/** Modal size */
size?: "xs" | "sm" | "md" | "lg";
/** Danger modal variant */
danger?: boolean;
/** Alert modal variant */
alert?: boolean;
/** Passive modal (no buttons) */
passiveModal?: boolean;
/** Modal content */
children?: React.ReactNode;
/** CSS class name */
className?: string;
/** Icon description for close button */
iconDescription?: string;
/** Primary button disabled */
primaryButtonDisabled?: boolean;
/** Secondary button disabled */
secondaryButtonDisabled?: boolean;
/** Prevent focus trap */
preventCloseOnClickOutside?: boolean;
/** Loading state */
primaryButtonLoading?: boolean;
/** Focus trap */
focusTrap?: boolean;
/** Container element selector */
selectorsFloatingMenus?: string[];
}
/**
* Modal wrapper for consistent behavior
*/
interface ModalWrapperProps {
/** Modal trigger button text */
buttonTriggerText?: string;
/** Button trigger className */
buttonTriggerClassName?: string;
/** Modal is open */
status?: "closed" | "open";
/** Handle open event */
handleOpen?: () => void;
/** Modal children */
children?: React.ReactNode;
/** Trigger button kind */
triggerButtonKind?: "primary" | "secondary" | "danger" | "ghost" | "tertiary";
/** Trigger button icon */
triggerButtonIconDescription?: string;
/** Disable trigger button */
disabled?: boolean;
/** Handle submit */
handleSubmit?: (event: React.MouseEvent<HTMLButtonElement>) => void;
/** Submit button text */
primaryButtonText?: string;
/** Handle secondary */
handleSecondarySubmit?: (event: React.MouseEvent<HTMLButtonElement>) => void;
/** Secondary button text */
secondaryButtonText?: string;
/** Modal heading */
modalHeading?: string;
/** Modal label */
modalLabel?: string;
/** Modal size */
size?: "xs" | "sm" | "md" | "lg";
/** Danger modal */
danger?: boolean;
/** Alert modal */
alert?: boolean;
/** Passive modal */
passiveModal?: boolean;
}
/**
* Composed modal for custom layouts
*/
interface ComposedModalProps {
/** Modal is open */
open: boolean;
/** Close handler */
onClose?: () => void;
/** Modal size */
size?: "xs" | "sm" | "md" | "lg";
/** Danger variant */
danger?: boolean;
/** Prevent close on outside click */
preventCloseOnClickOutside?: boolean;
/** Modal children */
children: React.ReactNode;
/** CSS class name */
className?: string;
/** Container selector */
selectorsFloatingMenus?: string[];
}
/**
* Modal header component
*/
interface ModalHeaderProps {
/** Header content */
children?: React.ReactNode;
/** Button icon description */
buttonOnClose?: () => void;
/** CSS class name */
className?: string;
/** Close icon description */
closeIconDescription?: string;
/** Icon description */
iconDescription?: string;
/** Modal label */
label?: string;
/** Modal title */
title?: string;
}
/**
* Modal body component
*/
interface ModalBodyProps {
/** Body content */
children?: React.ReactNode;
/** CSS class name */
className?: string;
/** Aria label */
"aria-label"?: string;
/** Has form */
hasForm?: boolean;
/** Has scrolling content */
hasScrollingContent?: boolean;
}
/**
* Modal footer component
*/
interface ModalFooterProps {
/** Footer content */
children?: React.ReactNode;
/** CSS class name */
className?: string;
/** Primary button text */
primaryButtonText?: string;
/** Primary button disabled */
primaryButtonDisabled?: boolean;
/** Primary click handler */
onRequestSubmit?: (event: React.MouseEvent<HTMLButtonElement>) => void;
/** Secondary button text */
secondaryButtonText?: string;
/** Secondary button disabled */
secondaryButtonDisabled?: boolean;
/** Secondary click handler */
onRequestClose?: (event: React.MouseEvent<HTMLButtonElement>) => void;
/** Danger variant */
danger?: boolean;
/** Close text */
closeText?: string;
/** Submit text */
submitText?: string;
}Usage Examples:
import {
Modal,
ModalWrapper,
ComposedModal,
ModalHeader,
ModalBody,
ModalFooter
} from "@carbon/react";
// Basic modal
<Modal
open={isModalOpen}
onRequestClose={() => setIsModalOpen(false)}
modalHeading="Delete item"
modalLabel="Confirmation"
primaryButtonText="Delete"
secondaryButtonText="Cancel"
danger
onRequestSubmit={handleDelete}
>
<p>Are you sure you want to delete this item? This action cannot be undone.</p>
</Modal>
// Modal with wrapper (trigger button included)
<ModalWrapper
buttonTriggerText="Open modal"
modalHeading="Add new item"
primaryButtonText="Add"
secondaryButtonText="Cancel"
handleSubmit={handleAdd}
>
<TextInput id="item-name" labelText="Item name" />
<TextArea id="description" labelText="Description" />
</ModalWrapper>
// Composed modal for custom layout
<ComposedModal open={isOpen} onClose={() => setIsOpen(false)} size="lg">
<ModalHeader
label="Settings"
title="User Preferences"
buttonOnClose={() => setIsOpen(false)}
/>
<ModalBody hasScrollingContent>
<Tabs>
<TabList>
<Tab>General</Tab>
<Tab>Privacy</Tab>
<Tab>Notifications</Tab>
</TabList>
<TabPanels>
<TabPanel>General settings content...</TabPanel>
<TabPanel>Privacy settings content...</TabPanel>
<TabPanel>Notification settings content...</TabPanel>
</TabPanels>
</Tabs>
</ModalBody>
<ModalFooter
primaryButtonText="Save"
secondaryButtonText="Cancel"
onRequestSubmit={handleSave}
onRequestClose={() => setIsOpen(false)}
/>
</ComposedModal>Contextual help and information tooltips with various positioning options.
/**
* Basic tooltip component
*/
interface TooltipProps {
/** Tooltip content */
children: React.ReactNode;
/** Tooltip text */
label: string;
/** Tooltip description */
description?: string;
/** Tooltip position */
align?:
| "top"
| "top-left"
| "top-right"
| "bottom"
| "bottom-left"
| "bottom-right"
| "left"
| "right";
/** Show tooltip on focus */
showIcon?: boolean;
/** Icon description */
iconDescription?: string;
/** Tooltip trigger type */
triggerClassName?: string;
/** Tooltip text */
tooltipText?: string;
/** Default open */
defaultOpen?: boolean;
/** Auto align */
autoAlign?: boolean;
/** Close on activation */
closeOnActivation?: boolean;
/** Entry/exit delay */
enterDelayMs?: number;
/** Exit delay */
leaveDelayMs?: number;
}
/**
* Definition tooltip for terms and definitions
*/
interface DefinitionTooltipProps {
/** Term to define */
children: React.ReactNode;
/** Definition text */
definition: string;
/** Tooltip position */
align?:
| "top"
| "top-left"
| "top-right"
| "bottom"
| "bottom-left"
| "bottom-right"
| "left"
| "right";
/** Trigger type */
triggerClassName?: string;
/** Default open state */
defaultOpen?: boolean;
/** Open state (controlled) */
open?: boolean;
/** Open change handler */
onOpenChange?: (open: boolean) => void;
}Usage Examples:
import { Tooltip, DefinitionTooltip, Button } from "@carbon/react";
import { Information } from "@carbon/react/icons";
// Basic tooltip
<Tooltip label="This button saves your changes" align="top">
<Button>Save</Button>
</Tooltip>
// Tooltip with description
<Tooltip
label="Autosave"
description="Your changes are automatically saved every 30 seconds"
align="bottom"
>
<Button hasIconOnly iconDescription="Autosave enabled">
<Information />
</Button>
</Tooltip>
// Definition tooltip
<p>
Our product uses{" "}
<DefinitionTooltip
definition="Machine learning algorithms that can understand and generate human-like text"
align="bottom"
>
artificial intelligence
</DefinitionTooltip>{" "}
to improve user experience.
</p>Interactive tooltip that remains open until dismissed, perfect for forms and help content.
/**
* Toggletip component for interactive tooltips
*/
interface ToggletipProps {
/** Toggletip content */
children: React.ReactNode;
/** Default open state */
defaultOpen?: boolean;
/** Open state (controlled) */
open?: boolean;
/** Open change handler */
onOpenChange?: (open: boolean) => void;
/** CSS class name */
className?: string;
}
/**
* Toggletip button trigger
*/
interface ToggletipButtonBaseProps extends React.ComponentPropsWithoutRef<"button"> {
/** Button content */
children: React.ReactNode;
/** Button label for accessibility */
label?: string;
}
/**
* Toggletip content container
*/
interface ToggletipContentProps {
/** Content children */
children: React.ReactNode;
/** CSS class name */
className?: string;
}
/**
* Toggletip actions container
*/
interface ToggleTipActionsProps {
/** Action children */
children: React.ReactNode;
/** CSS class name */
className?: string;
}Usage Examples:
import {
Toggletip,
ToggletipButton,
ToggletipContent,
ToggletipActions,
Button,
Link
} from "@carbon/react";
import { Information } from "@carbon/react/icons";
<Toggletip>
<ToggletipButton label="Additional information">
<Information />
</ToggletipButton>
<ToggletipContent>
<p>
This field accepts email addresses in the standard format.
For example: user@example.com
</p>
<ToggletipActions>
<Link href="/help/email-format">Learn more</Link>
<Button size="sm" kind="ghost">Got it</Button>
</ToggletipActions>
</ToggletipContent>
</Toggletip>Advanced positioning component for custom overlay content.
/**
* Popover positioning component
*/
interface PopoverProps {
/** Popover is open */
open?: boolean;
/** Drop direction */
dropShadow?: boolean;
/** High contrast */
highContrast?: boolean;
/** Light variant */
light?: boolean;
/** Popover children */
children: React.ReactNode;
/** CSS class name */
className?: string;
/** Relative positioning */
relative?: boolean;
/** Caret positioning */
caret?: boolean;
/** Alignment */
align?:
| "top"
| "top-left"
| "top-right"
| "bottom"
| "bottom-left"
| "bottom-right"
| "left"
| "left-bottom"
| "left-top"
| "right"
| "right-bottom"
| "right-top";
/** Auto align */
autoAlign?: boolean;
}
/**
* Popover content container
*/
interface PopoverContentProps {
/** Content children */
children: React.ReactNode;
/** CSS class name */
className?: string;
}Usage Examples:
import { Popover, PopoverContent, Button } from "@carbon/react";
<Popover
open={isPopoverOpen}
align="bottom-left"
dropShadow
onRequestClose={() => setIsPopoverOpen(false)}
>
<Button onClick={() => setIsPopoverOpen(!isPopoverOpen)}>
Options
</Button>
<PopoverContent>
<div style={{ padding: '1rem' }}>
<h4>Quick Actions</h4>
<ul>
<li><Link href="#">Edit</Link></li>
<li><Link href="#">Duplicate</Link></li>
<li><Link href="#">Delete</Link></li>
</ul>
</div>
</PopoverContent>
</Popover>Right-click context menu for contextual actions.
/**
* Context menu hook for creating right-click menus
*/
interface ContextMenuProps {
/** Menu items */
children: React.ReactNode;
/** Menu is open */
open?: boolean;
/** Position of menu */
x?: number;
y?: number;
/** Close handler */
onClose?: () => void;
/** Size variant */
size?: "sm" | "md" | "lg";
/** Target element */
target?: React.RefObject<HTMLElement>;
}
/**
* Context menu hook
*/
function useContextMenu(): {
/** Open context menu */
open: (event: React.MouseEvent, data?: any) => void;
/** Close context menu */
close: () => void;
/** Menu is open */
isOpen: boolean;
/** Menu position */
position: { x: number; y: number };
/** Menu data */
data: any;
}Usage Examples:
import { useContextMenu, Menu, MenuItem } from "@carbon/react";
function MyComponent() {
const contextMenu = useContextMenu();
return (
<div
onContextMenu={(e) => {
e.preventDefault();
contextMenu.open(e, { itemId: 'item-1' });
}}
>
Right-click me for context menu
{contextMenu.isOpen && (
<Menu
open={contextMenu.isOpen}
x={contextMenu.position.x}
y={contextMenu.position.y}
onClose={contextMenu.close}
>
<MenuItem onClick={() => console.log('Edit', contextMenu.data)}>
Edit
</MenuItem>
<MenuItem onClick={() => console.log('Delete', contextMenu.data)}>
Delete
</MenuItem>
</Menu>
)}
</div>
);
}Dropdown menus and menu systems for navigation and actions.
/**
* Menu container component
*/
interface MenuProps {
/** Menu items */
children: React.ReactNode;
/** Menu is open */
open?: boolean;
/** Menu position */
x?: number;
y?: number;
/** Close handler */
onClose?: () => void;
/** Menu size */
size?: "xs" | "sm" | "md" | "lg";
/** Target element ref */
target?: React.RefObject<HTMLElement>;
/** Auto close on selection */
autoClose?: boolean;
}
/**
* Menu item component
*/
interface MenuItemProps extends React.ComponentPropsWithoutRef<"button"> {
/** Menu item content */
children: React.ReactNode;
/** Item is disabled */
disabled?: boolean;
/** Item kind */
kind?: "default" | "danger";
/** Item label */
label?: string;
/** Render icon */
renderIcon?: React.ComponentType<any>;
/** Shortcut text */
shortcut?: string;
}
/**
* Menu button component (button + menu)
*/
interface MenuButtonProps {
/** Button text */
children: React.ReactNode;
/** Menu items */
menu: React.ReactNode;
/** Button kind */
kind?: "primary" | "secondary" | "tertiary" | "ghost";
/** Button size */
size?: "sm" | "md" | "lg";
/** Button disabled */
disabled?: boolean;
/** Menu size */
menuSize?: "xs" | "sm" | "md" | "lg";
/** Menu alignment */
menuAlignment?: "top" | "bottom";
/** Flipped menu position */
flipped?: boolean;
}Usage Examples:
import { MenuButton, Menu, MenuItem } from "@carbon/react";
import { Add, Edit, Delete } from "@carbon/react/icons";
// Menu button with dropdown
<MenuButton
kind="primary"
menu={
<Menu>
<MenuItem renderIcon={Add}>Add item</MenuItem>
<MenuItem renderIcon={Edit}>Edit item</MenuItem>
<MenuItem renderIcon={Delete} kind="danger">Delete item</MenuItem>
</Menu>
}
>
Actions
</MenuButton>
// Standalone menu
<Menu open={isMenuOpen} onClose={() => setIsMenuOpen(false)}>
<MenuItem onClick={() => handleAction('save')}>
Save
</MenuItem>
<MenuItem onClick={() => handleAction('export')}>
Export
</MenuItem>
<MenuItem disabled>
Print (unavailable)
</MenuItem>
</Menu>/**
* Toast notification (temporary)
*/
interface ToastNotificationProps {
/** Notification kind */
kind?: "error" | "info" | "info-square" | "success" | "warning" | "warning-alt";
/** Notification title */
title: string;
/** Notification subtitle */
subtitle?: string;
/** Notification caption */
caption?: string;
/** Close handler */
onClose?: () => void;
/** Close button description */
closeButtonDescription?: string;
/** Notification role */
role?: "alert" | "log" | "status";
/** Timeout in milliseconds */
timeout?: number;
/** Hide close button */
hideCloseButton?: boolean;
/** Low contrast */
lowContrast?: boolean;
}
/**
* Inline notification (persistent)
*/
interface InlineNotificationProps {
/** Notification kind */
kind?: "error" | "info" | "info-square" | "success" | "warning" | "warning-alt";
/** Notification title */
title: string;
/** Notification subtitle */
subtitle?: string;
/** Close handler */
onClose?: () => void;
/** Close button description */
closeButtonDescription?: string;
/** Notification role */
role?: "alert" | "log" | "status";
/** Hide close button */
hideCloseButton?: boolean;
/** Low contrast */
lowContrast?: boolean;
/** Action button */
actions?: React.ReactNode;
}