Dropdown
A dropdown menu component for displaying contextual actions and options. Supports anchoring, portals, keyboard navigation, and nested submenus.
Import
import { Dropdown, DropdownItem } from 'nightwatch-ui';
Basic Usage
function BasicDropdown() {
const [showDropdown, setShowDropdown] = useState(false);
const buttonRef = useRef<HTMLDivElement>(null);
return (
<>
<IconButton
ref={buttonRef}
icon={Icon.More}
onClick={() => setShowDropdown(!showDropdown)}
/>
<Dropdown
buttonRef={buttonRef}
showDropdown={showDropdown}
setShowDropdown={setShowDropdown}
>
<DropdownItem label="Edit" icon={Icon.Edit} onClick={handleEdit} />
<DropdownItem label="Share" icon={Icon.Share} onClick={handleShare} />
<DropdownItem label="Delete" icon={Icon.Trash} onClick={handleDelete} color="destructive" />
</Dropdown>
</>
);
}
With Search
function SearchableDropdown() {
const [showDropdown, setShowDropdown] = useState(false);
const [search, setSearch] = useState('');
const buttonRef = useRef<HTMLDivElement>(null);
return (
<Dropdown
buttonRef={buttonRef}
showDropdown={showDropdown}
setShowDropdown={setShowDropdown}
inputField={
<InputField
value={search}
onChange={(e) => setSearch(e.target.value)}
icon={Icon.Search}
placeholder="Search..."
/>
}
>
<DropdownItem label="Option 1" onClick={handleOption1} />
<DropdownItem label="Option 2" onClick={handleOption2} />
</Dropdown>
);
}
Portal Mode
<Dropdown
buttonRef={buttonRef}
showDropdown={showDropdown}
setShowDropdown={setShowDropdown}
portal // Renders in a portal for z-index control
>
<DropdownItem label="Action 1" onClick={handleAction1} />
<DropdownItem label="Action 2" onClick={handleAction2} />
</Dropdown>
Custom Anchor Position
<Dropdown
customAnchor={{ x: 100, y: 200 }}
showDropdown={showDropdown}
setShowDropdown={setShowDropdown}
portal
>
<DropdownItem label="Context action" onClick={handleAction} />
</Dropdown>
Dropdown Props
Controls dropdown visibility
setShowDropdown
(open: boolean) => void
required
Callback to update dropdown visibility state
children
React.ReactNode | DropdownItemComponent[]
required
Dropdown content, typically DropdownItem components
buttonRef
React.MutableRefObject<HTMLDivElement | null>
Ref to the button/element that triggers the dropdown
Custom position for the dropdown instead of anchoring to a button
Renders the dropdown in a React portal for better z-index control
Input field rendered at the top of the dropdown for search/filter
Makes dropdown match the width of the anchor element
Maximum dropdown height. Enables scrolling when content exceeds this height
Gap in pixels between the anchor and the dropdown
Removes default padding from the dropdown
Marks this dropdown as a submenu. Controls opening direction and behavior
Configuration for keyboard navigation support
Custom z-index for the dropdown
customBackgroundBlockerPos
{ top?: number; left?: number }
Custom position for the background blocker element
Custom mouse event type for outside click detection
Test identifier for e2e tests
DropdownItem
Individual item component within a dropdown menu.
Basic Usage
<DropdownItem
label="Edit"
icon={Icon.Edit}
onClick={handleEdit}
/>
With Icons
<DropdownItem
label="Delete"
icon={Icon.Trash}
color="destructive"
onClick={handleDelete}
/>
Active State
<DropdownItem
label="Option 1"
active={selectedOption === 'option1'}
onClick={() => setSelectedOption('option1')}
/>
Disabled State
<DropdownItem
label="Unavailable Action"
disabled
onClick={handleAction}
/>
Custom Elements
<DropdownItem
label="Custom"
startElement={<CustomIcon />}
endElement={<Badge count={5} />}
onClick={handleClick}
/>
DropdownItem Props
Text or content to display in the dropdown item
onClick
(e?: React.MouseEvent) => void | Promise<void>
Callback fired when the item is clicked
Icon displayed at the start of the item
color
DropdownItemColor
default:"primary"
Content color. Options:
"primary" - Default primary color
"destructive" - Red/destructive color for dangerous actions
Shows a check mark to indicate active/selected state
Disables the item, preventing clicks and showing disabled state
size
DropdownItemSize
default:"Size.MEDIUM"
Item size. Options: Size.MEDIUM, Size.LARGE
Controls hover/highlight state. Used for keyboard navigation
Automatically scrolls this item into view
Custom element displayed at the start of the item
Custom element displayed at the end of the item
Controls visibility of the end element. Defaults to true if endElement is provided (on desktop)
Custom JSX to replace the default label rendering
Hides the bottom divider on mobile
Removes default padding from the item
Callback fired when the item is hovered
Optional value associated with the item
Test identifier for e2e tests
Examples
function ContextMenu() {
const [showMenu, setShowMenu] = useState(false);
const [position, setPosition] = useState({ x: 0, y: 0 });
const handleContextMenu = (e: React.MouseEvent) => {
e.preventDefault();
setPosition({ x: e.clientX, y: e.clientY });
setShowMenu(true);
};
return (
<>
<div onContextMenu={handleContextMenu}>
Right-click me
</div>
<Dropdown
customAnchor={position}
showDropdown={showMenu}
setShowDropdown={setShowMenu}
portal
>
<DropdownItem label="Copy" icon={Icon.Copy} onClick={handleCopy} />
<DropdownItem label="Paste" icon={Icon.Paste} onClick={handlePaste} />
<DropdownItem label="Delete" icon={Icon.Trash} color="destructive" onClick={handleDelete} />
</Dropdown>
</>
);
}
function SelectionMenu() {
const [selected, setSelected] = useState('option1');
const [showMenu, setShowMenu] = useState(false);
const buttonRef = useRef<HTMLDivElement>(null);
const options = [
{ value: 'option1', label: 'Option 1', icon: Icon.File },
{ value: 'option2', label: 'Option 2', icon: Icon.Folder },
{ value: 'option3', label: 'Option 3', icon: Icon.Archive }
];
return (
<>
<Button
ref={buttonRef}
onClick={() => setShowMenu(!showMenu)}
>
{options.find(o => o.value === selected)?.label}
</Button>
<Dropdown
buttonRef={buttonRef}
showDropdown={showMenu}
setShowDropdown={setShowMenu}
>
{options.map(option => (
<DropdownItem
key={option.value}
label={option.label}
icon={option.icon}
active={selected === option.value}
onClick={() => {
setSelected(option.value);
setShowMenu(false);
}}
/>
))}
</Dropdown>
</>
);
}