Skip to main content

Dropdown Components

Proton provides dropdown components for menus, actions, and select inputs with full keyboard navigation and accessibility support. The main dropdown component with popper positioning. Location: components/dropdown/Dropdown.tsx

Basic Usage

import { useRef, useState } from 'react';
import { Button } from '@proton/atoms/Button/Button';
import Dropdown from '@proton/components/components/dropdown/Dropdown';
import DropdownMenu from '@proton/components/components/dropdown/DropdownMenu';
import DropdownMenuButton from '@proton/components/components/dropdown/DropdownMenuButton';

const MyDropdown = () => {
  const anchorRef = useRef<HTMLButtonElement>(null);
  const [isOpen, setIsOpen] = useState(false);

  return (
    <>
      <Button ref={anchorRef} onClick={() => setIsOpen(!isOpen)}>
        Actions
      </Button>
      
      <Dropdown
        isOpen={isOpen}
        anchorRef={anchorRef}
        onClose={() => setIsOpen(false)}
      >
        <DropdownMenu>
          <DropdownMenuButton onClick={() => console.log('Edit')}>
            Edit
          </DropdownMenuButton>
          <DropdownMenuButton onClick={() => console.log('Delete')}>
            Delete
          </DropdownMenuButton>
        </DropdownMenu>
      </Dropdown>
    </>
  );
};

Props

anchorRef
RefObject<HTMLElement>
required
Reference to the element that triggers the dropdown
isOpen
boolean
Whether the dropdown is open. Default: false
onClose
(event?) => void
Callback when dropdown should close
onClosed
() => void
Callback when dropdown animation completes
originalPlacement
PopperPlacement
Initial placement of dropdown. Default: bottom
availablePlacements
PopperPlacement[]
Array of allowed placements for auto-positioning
size
DropdownSize
Dropdown dimensions configuration
offset
number
Distance from anchor element in pixels. Default: 8
noCaret
boolean
Hide the caret/arrow pointing to anchor. Default: false
autoClose
boolean
Auto close on item click. Default: true
autoCloseOutside
boolean
Auto close when clicking outside. Default: true
autoCloseOutsideAnchor
boolean
Auto close when clicking outside anchor. Default: true
disableFocusTrap
boolean
Disable focus trap. Default: false
disableDefaultArrowNavigation
boolean
Disable arrow key navigation. Default: false
adaptiveForTouchScreens
boolean
Adapt UI for touch screens. Default: true
borderRadius
DropdownBorderRadius
Border radius size: xl, lg, md, sm. Default: md
contentProps
ContentProps
Props passed to content container

Examples

<Dropdown isOpen={isOpen} anchorRef={anchorRef} onClose={onClose}>
  <DropdownMenu>
    <DropdownMenuButton onClick={handleEdit}>Edit</DropdownMenuButton>
    <DropdownMenuButton onClick={handleDuplicate}>Duplicate</DropdownMenuButton>
    <DropdownMenuButton onClick={handleDelete}>Delete</DropdownMenuButton>
  </DropdownMenu>
</Dropdown>
Wrapper for dropdown menu items. Location: components/dropdown/DropdownMenu.tsx

Usage

import DropdownMenu from '@proton/components/components/dropdown/DropdownMenu';

<DropdownMenu>
  {/* Menu items here */}
</DropdownMenu>
Clickable menu item button. Location: components/dropdown/DropdownMenuButton.tsx

Usage

import DropdownMenuButton from '@proton/components/components/dropdown/DropdownMenuButton';

<DropdownMenuButton onClick={handleAction}>
  Action Label
</DropdownMenuButton>

Props

onClick
() => void
Click handler
disabled
boolean
Disable the button
className
string
Additional CSS classes
Link menu item for navigation. Location: components/dropdown/DropdownMenuLink.tsx

Usage

import DropdownMenuLink from '@proton/components/components/dropdown/DropdownMenuLink';

<DropdownMenuLink href="/settings">
  Settings
</DropdownMenuLink>

SimpleDropdown

Simplified dropdown with built-in button. Location: components/dropdown/SimpleDropdown.tsx

Usage

import SimpleDropdown from '@proton/components/components/dropdown/SimpleDropdown';
import DropdownMenu from '@proton/components/components/dropdown/DropdownMenu';
import DropdownMenuButton from '@proton/components/components/dropdown/DropdownMenuButton';

const MySimpleDropdown = () => {
  return (
    <SimpleDropdown content="More Actions">
      <DropdownMenu>
        <DropdownMenuButton onClick={handleEdit}>Edit</DropdownMenuButton>
        <DropdownMenuButton onClick={handleDelete}>Delete</DropdownMenuButton>
      </DropdownMenu>
    </SimpleDropdown>
  );
};

SelectTwo

Advanced select component with search and keyboard navigation. Location: components/selectTwo/SelectTwo.tsx

Basic Usage

import { useState } from 'react';
import SelectTwo from '@proton/components/components/selectTwo/SelectTwo';
import Option from '@proton/components/components/option/Option';

const MySelect = () => {
  const [value, setValue] = useState('option1');

  return (
    <SelectTwo
      value={value}
      onChange={({ value }) => setValue(value)}
    >
      <Option value="option1" title="Option 1">Option 1</Option>
      <Option value="option2" title="Option 2">Option 2</Option>
      <Option value="option3" title="Option 3">Option 3</Option>
    </SelectTwo>
  );
};

Props

value
V
required
Currently selected value
onChange
({ value, selectedIndex }) => void
Called when selection changes
onValue
(value: V) => void
Alternative change handler receiving only value
multiple
boolean
Enable multiple selection. Default: false
placeholder
string
Placeholder text when no selection
unstyled
boolean
Remove border styling. Default: false
disabled
boolean
Disable the select
fullWidth
boolean
Take full width of container
noDropdownCaret
boolean
Hide the dropdown caret icon
clearSearchAfter
number
Milliseconds to clear search input. Default: 500
getSearchableValue
(value: V) => string
Function to extract searchable string from complex values
renderSelected
(value: V) => ReactNode
Custom render function for selected value
size
DropdownSize
Dropdown size configuration
originalPlacement
PopperPlacement
Dropdown placement
dropdownHeading
ReactNode
Optional heading above options

Examples

<SelectTwo value={value} onChange={({ value }) => setValue(value)}>
  <Option value="1">Option 1</Option>
  <Option value="2">Option 2</Option>
  <Option value="3">Option 3</Option>
</SelectTwo>

Best Practices

Managing Dropdown State

const [isOpen, setIsOpen] = useState(false);
const anchorRef = useRef<HTMLButtonElement>(null);

const handleToggle = () => setIsOpen(!isOpen);
const handleClose = () => setIsOpen(false);

return (
  <>
    <Button ref={anchorRef} onClick={handleToggle}>
      Menu
    </Button>
    <Dropdown
      isOpen={isOpen}
      anchorRef={anchorRef}
      onClose={handleClose}
    >
      {/* Content */}
    </Dropdown>
  </>
);

Keyboard Navigation

Dropdowns support:
  • Arrow keys to navigate items
  • Enter/Space to select
  • Escape to close
  • Type to search (when enabled)

Accessibility

<Button
  ref={anchorRef}
  onClick={handleToggle}
  aria-expanded={isOpen}
  aria-haspopup="true"
>
  Actions
</Button>

<Dropdown
  isOpen={isOpen}
  anchorRef={anchorRef}
  onClose={handleClose}
  role="menu"
>
  <DropdownMenuButton role="menuitem">
    Action
  </DropdownMenuButton>
</Dropdown>

Positioning

Control dropdown placement:
// Open above the anchor
<Dropdown originalPlacement="top" />

// Open to the right
<Dropdown originalPlacement="right" />

// Auto-adjust with fallbacks
<Dropdown
  originalPlacement="bottom"
  availablePlacements={['bottom', 'top', 'left', 'right']}
/>

Source Code

View source:
  • Dropdown: packages/components/components/dropdown/Dropdown.tsx:1
  • SelectTwo: packages/components/components/selectTwo/SelectTwo.tsx:1
  • SimpleDropdown: packages/components/components/dropdown/SimpleDropdown.tsx:1

Build docs developers (and LLMs) love