Skip to content

fix(popup-menu,combobox): match search words in any order - #599

Draft
kianbazza wants to merge 1 commit into
canaryfrom
ui-654-match-menu-search-words-in-any-order
Draft

kianbazza wants to merge 1 commit into
canaryfrom
ui-654-match-menu-search-words-in-any-order

Conversation

@kianbazza

@kianbazza kianbazza commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Menu search matched the whole query as one in-order run over value, then keywords, then the values of a row's tree parents. A tree row reads "Navattic › New project", but only "new navattic" found it. Data-first menus ignore a consumer filter, so consumers couldn't work around this.

defaultFilter now accepts the words of a query in any order. ListboxStore (children-based menus, select, combobox) and data-first scoreNodes both use it as their default:

defaultFilter(value, query, keywords)
  inOrder = commandScore(value, query, keywords)        # today's score
  if query has one word: return inOrder               # single-word ranking unchanged
  anyOrder = product of commandScore(value, word, keywords) per word   # 0 if any word misses
  return max(inOrder, anyOrder)

scoreNodes (tree rows, multi-word query)
  if the parent values alone don't match the query
    also try commandScore("<parents> <value>", query, ownKeywords)    # reading order ranks ≥ reverse

The parent-only check keeps a query like "new project" from lifting every child of a "New project templates" tree above a closer "Create new project" row. commandScore itself is unchanged and still exported.

Evidence

A tree with "Navattic › New project", "Navattic › Starter-chip matching" and "Acme › New project", run through filterNodes (tree-nodes.test.ts):

Query Before After
navattic new no results Navattic › New project
new navattic Navattic › New project Navattic › New project
nav proj no results Navattic › New project
navattic starter no results Navattic › Starter-chip matching
starter navattic Navattic › Starter-chip matching Navattic › Starter-chip matching
navattic xyz no results no results
before:  × finds the row for "navattic new" in any word order
         × finds the row for "nav proj" in any word order
         × finds the row for "navattic starter" in any word order
         × ranks the breadcrumb order at least as high as the reverse
         × defaultFilter › matches the words of a query in any order
         × defaultFilter › matches each word fuzzily
after:   all pass

Single-word scores are pinned equal to commandScore, including padded and hyphenated queries, and a "de" ranking across four items is pinned. Single-word tree results keep their existing order.

Merge Danger

Door: two-way

Revert the commit to get the old matching back. No data or API shape changes.

Blast Radius: search

Every menu, command menu, select and combobox using the default filter gets this, as does any consumer calling defaultFilter directly. Multi-word queries match more than before: each word only has to match somewhere, so short words like "e e" match broadly. Results that matched before never score lower, but they can be outranked by rows that newly match. Multi-word queries cost roughly 2–3× more scoring per keystroke. Single-word queries behave the same as before.

Closes UI-654

Search now matches the words of a query in any order, so a tree row shown as "Navattic › New project" is found by "navattic new" as well as "new navattic". Single-word searches score as before; `commandScore` is unchanged.

Closes UI-654
@vercel

vercel Bot commented Oct 20, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
ui-canary Ready Ready Preview Oct 20, 2026 7:48pm UTC

Request Review

@linear-code

linear-code Bot commented Oct 20, 2026

Copy link
Copy Markdown

UI-654

This branch was successfully deployed

1 active deployment
Preview – ui-canary — 11f26368 Deployed Oct 20, 2026 by vercel[bot]
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