Skip to content

Feat/search dropdown#114

Open
giuliana-gladeye wants to merge 3 commits into
mainfrom
feat/search-dropdown
Open

Feat/search dropdown#114
giuliana-gladeye wants to merge 3 commits into
mainfrom
feat/search-dropdown

Conversation

@giuliana-gladeye

@giuliana-gladeye giuliana-gladeye commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

Added search to DropdownMenu

Adds an optional search box to our existing DropdownMenu so you can filter items in place. It's opt-in per menu — if a menu doesn't have a <DropdownMenuSearch /> in it, nothing changes and Radix's normal typeahead still works. Everything is wired through a small internal context, so the usage stays the same, you just drop new parts into DropdownMenuContent.

What's new

  • <DropdownMenuSearch /> — a search input you put inside DropdownMenuContent. Hidden by default and reveals when you start typing. Pass alwaysVisible if you want it showing straight away.
  • <DropdownMenuEmpty /> — a "no results" row that only shows when the query doesn't match any items.
  • DropdownMenuItem / CheckboxItem / RadioItem hide themselves when they don't match. Matches on textValue, falling back to the item's text.
  • Submenus flatten while searching — nested items get pulled into the main list so they're searchable too.

Usage

<DropdownMenu>
  <DropdownMenuTrigger asChild>
    <Button size="sm" variant="tertiary">
      {assignee ? `Assigned: ${assignee}` : 'Assign reviewer'}
    </Button>
  </DropdownMenuTrigger>
  <DropdownMenuContent align="start">
    <DropdownMenuSearch placeholder="Search members..." />
    <DropdownMenuLabel>Team members</DropdownMenuLabel>
    {MEMBERS.map((person) => (
      <DropdownMenuItem
        key={person.name}
        textValue={person.name}
        onSelect={() => setAssignee(person.name)}
      >
        <Icon icon={person.icon} size="xs" background="circle" elevation="raised" />
        <span>{person.name}</span>
      </DropdownMenuItem>
    ))}
    <DropdownMenuEmpty>No members found</DropdownMenuEmpty>
  </DropdownMenuContent>
</DropdownMenu>

If an item has an icon/avatar instead of plain text, give it a textValue so it filters properly.

Heads up

Most of this is working around how Radix handles focus and keyboard:

  • We get in front of Radix's typeahead by handling the key on Content and calling preventDefault() — Radix bails when the event's already defaultPrevented.
  • Arrow keys from the search box jump into the list manually, because Radix won't do it when focus is on the input.
  • Submenus flatten by rendering the SubContent's children inline while searching — Radix keeps sub items in a separate popover that isn't mounted during a top-level search, so there's no other way to filter them.
  • Query resets on open, not close — otherwise selecting an item clears the filter mid-close and the full list flashes back before it disappears.

Known gaps

  • ArrowUp on the first item won't go back to the search box (Radix menus don't loop).
  • Flattening only works if the child is our exported DropdownMenuSubContent — wrapping it breaks it.

Extras

  • Updated DropdownMenuLabel styling, since it looked the same as a clickable item making it confusing.
  • Added <DropdownMenuSearch /> to both RadioDropdown and FilterDropdown components. We need to update the docs for them after feat/docs get's merged.
  • Should we add it to SortSelector component too @Shrinks99 ??
Screen.Recording.2026-07-14.at.5.33.05.PM.mov
screencapture-localhost-4321-components-dropdown-menu-2026-07-14-17_32_25

Linear ticket

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant