Skip to main content
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>
    </>
  );
}
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>
showDropdown
boolean
default:true
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
customAnchor
{ x: number; y: number }
Custom position for the dropdown instead of anchoring to a button
portal
boolean
default:false
Renders the dropdown in a React portal for better z-index control
inputField
InputComponent
Input field rendered at the top of the dropdown for search/filter
fullWidth
boolean
default:false
Makes dropdown match the width of the anchor element
width
number | string
Custom dropdown width
minWidth
number | string
Minimum dropdown width
maxWidth
number | string
Maximum dropdown width
maxHeight
number | string
Maximum dropdown height. Enables scrolling when content exceeds this height
gapFromAnchor
number
default:0
Gap in pixels between the anchor and the dropdown
noPadding
boolean
default:false
Removes default padding from the dropdown
isSubmenu
boolean
default:false
Marks this dropdown as a submenu. Controls opening direction and behavior
keyboardNavControls
KeyboardNavControls
Configuration for keyboard navigation support
zIndex
number
Custom z-index for the dropdown
customBackgroundBlockerPos
{ top?: number; left?: number }
Custom position for the background blocker element
clickOutsideWebListener
MouseClickEvents
Custom mouse event type for outside click detection
className
string
Custom CSS class name
id
string
HTML id attribute
dataTest
string
Test identifier for e2e tests
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}
/>
label
React.ReactNode
required
Text or content to display in the dropdown item
onClick
(e?: React.MouseEvent) => void | Promise<void>
Callback fired when the item is clicked
icon
Icon | IconComponent
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
active
boolean
default:false
Shows a check mark to indicate active/selected state
disabled
boolean
default:false
Disables the item, preventing clicks and showing disabled state
size
DropdownItemSize
default:"Size.MEDIUM"
Item size. Options: Size.MEDIUM, Size.LARGE
highlight
boolean
Controls hover/highlight state. Used for keyboard navigation
scrollIntoView
boolean
default:false
Automatically scrolls this item into view
startElement
JSX.Element
Custom element displayed at the start of the item
endElement
JSX.Element
Custom element displayed at the end of the item
showEndElement
boolean
Controls visibility of the end element. Defaults to true if endElement is provided (on desktop)
customLabel
JSX.Element
Custom JSX to replace the default label rendering
hideDivider
boolean
Hides the bottom divider on mobile
noPadding
boolean
default:false
Removes default padding from the item
onHover
() => void
Callback fired when the item is hovered
value
string
Optional value associated with the item
dataTest
string
Test identifier for e2e tests

Examples

Context Menu

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>
    </>
  );
}

Selection Menu

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>
    </>
  );
}

Build docs developers (and LLMs) love