Skip to main content

Dropdown

** Last Built**: September 2, 2025 at 4:19 PM A clean, accessible dropdown menu component that follows Headless UI design principles. Features keyboard navigation, proper ARIA attributes, and flexible customization options.

Basic Usage

Live Editor
<Dropdown
  trigger={
    <button className='px-4 py-2 bg-blue-600 text-white rounded-md'>
      Click me
    </button>
  }
  items={[
    { label: 'Edit', value: 'edit', onClick: () => alert('Edit clicked') },
    {
      label: 'Delete',
      value: 'delete',
      onClick: () => alert('Delete clicked'),
    },
    { label: 'View', value: 'view', onClick: () => alert('View clicked') },
  ]}
/>
Result
Loading...

With Icons

Add icons to your dropdown items for better visual communication:

Live Editor
<Dropdown
  trigger={
    <button className='px-4 py-2 bg-gray-600 text-white rounded-md'>
      Actions
    </button>
  }
  items={[
    {
      label: 'Edit Profile',
      value: 'edit',
      onClick: () => alert('Edit Profile clicked'),
      icon: <span></span>,
    },
    {
      label: 'Settings',
      value: 'settings',
      onClick: () => alert('Settings clicked'),
      icon: <span></span>,
    },
    {
      label: 'Logout',
      value: 'logout',
      onClick: () => alert('Logout clicked'),
      icon: <span></span>,
    },
  ]}
/>
Result
Loading...

With Dividers

Use dividers to group related items:

Live Editor
<Dropdown
  trigger={
    <button className='px-4 py-2 bg-green-600 text-white rounded-md'>
      More Options
    </button>
  }
  items={[
    { label: 'Save', value: 'save', onClick: () => alert('Save clicked') },
    {
      label: 'Export',
      value: 'export',
      onClick: () => alert('Export clicked'),
    },
    { divider: true },
    {
      label: 'Delete',
      value: 'delete',
      onClick: () => alert('Delete clicked'),
    },
  ]}
/>
Result
Loading...

Disabled Items

Disable specific items when they're not applicable:

Live Editor
<Dropdown
  trigger={
    <button className='px-4 py-2 bg-purple-600 text-white rounded-md'>
      User Actions
    </button>
  }
  items={[
    { label: 'Edit', value: 'edit', onClick: () => alert('Edit clicked') },
    {
      label: 'Delete',
      value: 'delete',
      onClick: () => alert('Delete clicked'),
      disabled: true,
    },
    { label: 'View', value: 'view', onClick: () => alert('View clicked') },
  ]}
/>
Result
Loading...

Alignment Options

Control how the dropdown menu aligns with the trigger:

Live Editor
<div className='flex gap-4'>
  <Dropdown
    trigger={
      <button className='px-4 py-2 bg-blue-600 text-white rounded-md'>
        Left
      </button>
    }
    items={[
      { label: 'Option 1', value: '1', onClick: () => alert('Option 1') },
      { label: 'Option 2', value: '2', onClick: () => alert('Option 2') },
    ]}
    align='left'
  />
  <Dropdown
    trigger={
      <button className='px-4 py-2 bg-green-600 text-white rounded-md'>
        Center
      </button>
    }
    items={[
      { label: 'Option 1', value: '1', onClick: () => alert('Option 1') },
      { label: 'Option 2', value: '2', onClick: () => alert('Option 2') },
    ]}
    align='center'
  />
  <Dropdown
    trigger={
      <button className='px-4 py-2 bg-purple-600 text-white rounded-md'>
        Right
      </button>
    }
    items={[
      { label: 'Option 1', value: '1', onClick: () => alert('Option 1') },
      { label: 'Option 2', value: '2', onClick: () => alert('Option 2') },
    ]}
    align='right'
  />
</div>
Result
Loading...

Size Variants

Choose from different menu widths:

Live Editor
<div className='flex gap-4'>
  <Dropdown
    trigger={
      <button className='px-4 py-2 bg-blue-600 text-white rounded-md'>
        Small
      </button>
    }
    items={[
      { label: 'Short', value: 'short', onClick: () => alert('Short') },
      { label: 'Text', value: 'text', onClick: () => alert('Text') },
    ]}
    size='sm'
  />
  <Dropdown
    trigger={
      <button className='px-4 py-2 bg-green-600 text-white rounded-md'>
        Medium
      </button>
    }
    items={[
      {
        label: 'Medium length text',
        value: 'medium',
        onClick: () => alert('Medium'),
      },
      {
        label: 'Another option',
        value: 'option',
        onClick: () => alert('Option'),
      },
    ]}
    size='md'
  />
  <Dropdown
    trigger={
      <button className='px-4 py-2 bg-purple-600 text-white rounded-md'>
        Large
      </button>
    }
    items={[
      {
        label: 'Very long dropdown item text that needs more space',
        value: 'long',
        onClick: () => alert('Long'),
      },
      {
        label: 'Another very long option text',
        value: 'another',
        onClick: () => alert('Another'),
      },
    ]}
    size='lg'
  />
</div>
Result
Loading...

Custom Styling

Apply custom classes to different parts of the dropdown:

Live Editor
<Dropdown
  trigger={
    <button className='px-4 py-2 bg-gradient-to-r from-pink-500 to-purple-500 text-white rounded-md'>
      Custom Styled
    </button>
  }
  items={[
    { label: 'Custom Item 1', value: '1', onClick: () => alert('Custom 1') },
    { label: 'Custom Item 2', value: '2', onClick: () => alert('Custom 2') },
  ]}
  className='custom-dropdown'
  triggerClassName='custom-trigger'
  menuClassName='custom-menu'
/>
Result
Loading...

Advanced Configuration

Control dropdown behavior with advanced options:

Live Editor
<Dropdown
  trigger={
    <button className='px-4 py-2 bg-orange-600 text-white rounded-md'>
      Advanced
    </button>
  }
  items={[
    {
      label: 'Keep Open',
      value: 'keep',
      onClick: () => alert('This keeps the menu open'),
    },
    {
      label: 'Close After',
      value: 'close',
      onClick: () => alert('This closes the menu'),
    },
  ]}
  closeOnSelect={false}
  closeOnClickOutside={false}
/>
Result
Loading...

Real-world Examples

User Profile Menu

Live Editor
<Dropdown
  trigger={
    <div className='flex items-center gap-2 px-3 py-2 bg-gray-100 rounded-md cursor-pointer hover:bg-gray-200'>
      <div className='w-8 h-8 bg-blue-500 rounded-full flex items-center justify-center text-white font-semibold'>
        JD
      </div>
      <span className='text-gray-700'>John Doe</span>
      <span className='text-gray-400'></span>
    </div>
  }
  items={[
    {
      label: 'Profile',
      value: 'profile',
      onClick: () => alert('Profile'),
      icon: <span></span>,
    },
    {
      label: 'Settings',
      value: 'settings',
      onClick: () => alert('Settings'),
      icon: <span></span>,
    },
    { divider: true },
    {
      label: 'Help',
      value: 'help',
      onClick: () => alert('Help'),
      icon: <span></span>,
    },
    {
      label: 'Logout',
      value: 'logout',
      onClick: () => alert('Logout'),
      icon: <span></span>,
    },
  ]}
  align='right'
/>
Result
Loading...

Data Table Actions

Live Editor
<div className='flex gap-2'>
  <Dropdown
    trigger={
      <button className='px-3 py-1 bg-blue-600 text-white text-sm rounded hover:bg-blue-700'>
        Actions
      </button>
    }
    items={[
      {
        label: 'View Details',
        value: 'view',
        onClick: () => alert('View Details'),
      },
      {
        label: 'Edit Record',
        value: 'edit',
        onClick: () => alert('Edit Record'),
      },
      { divider: true },
      {
        label: 'Duplicate',
        value: 'duplicate',
        onClick: () => alert('Duplicate'),
      },
      { label: 'Archive', value: 'archive', onClick: () => alert('Archive') },
      { divider: true },
      {
        label: 'Delete',
        value: 'delete',
        onClick: () => alert('Delete'),
        disabled: true,
      },
    ]}
    size='sm'
  />
  <Badge variant='success'>Active</Badge>
</div>
Result
Loading...

API Reference

Props

PropTypeDefaultDescription
triggerReactNode-The element that triggers the dropdown
itemsDropdownItem[]-Array of dropdown items
align'left' | 'right' | 'center''left'Menu alignment relative to trigger
size'sm' | 'md' | 'lg''md'Menu width size
classNamestring-Additional CSS classes for the dropdown container
triggerClassNamestring-Additional CSS classes for the trigger element
menuClassNamestring-Additional CSS classes for the menu
closeOnSelectbooleantrueWhether to close menu after item selection
closeOnClickOutsidebooleantrueWhether to close menu when clicking outside
PropertyTypeDescription
labelstringDisplay text for the item
valueanyValue associated with the item
onClick() => voidFunction called when item is clicked
disabledbooleanWhether the item is disabled
dividerbooleanWhether to render a divider line
iconReactNodeOptional icon to display before the label

Alignment Options

  • left: Menu aligns to the left edge of the trigger (default)
  • right: Menu aligns to the right edge of the trigger
  • center: Menu centers horizontally on the trigger

Size Options

  • sm: Small width (w-40 - 160px)
  • md: Medium width (w-48 - 192px) - default
  • lg: Large width (w-56 - 224px)

Accessibility

The Dropdown component is fully accessible and follows ARIA best practices:

  • Keyboard Navigation:
    • Enter or Space to open/close
    • Arrow Down to open
    • Escape to close
    • Tab navigation through menu items
  • Screen Reader Support: Proper ARIA attributes and roles
  • Focus Management: Automatic focus handling and restoration
  • Semantic Structure: Uses appropriate HTML elements and roles

Design Principles

The Dropdown component follows these design principles:

  • Minimal: Clean, simple design without unnecessary visual noise
  • Consistent: Uniform spacing and sizing across all variants
  • Accessible: High contrast and proper focus states
  • Flexible: Easy to customize and extend with custom classes
  • Semantic: Uses appropriate colors and spacing for visual hierarchy

Best Practices

  • Use dividers to group related actions logically
  • Keep item labels concise and descriptive
  • Use icons sparingly to enhance visual communication
  • Consider the alignment based on available space
  • Test keyboard navigation thoroughly
  • Use disabled states for unavailable actions
  • Keep the number of items reasonable (5-10 max)

Keyboard Shortcuts

KeyAction
EnterOpen/close dropdown or select item
SpaceOpen/close dropdown or select item
Arrow DownOpen dropdown
EscapeClose dropdown
TabNavigate through menu items