React components for the Carbon Design System, IBM's comprehensive design system providing production-ready UI components
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
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;
}Install with Tessl CLI
npx tessl i tessl/npm-carbon--react