Search
How the query matches and ranks rows, and how to swap in your own matcher.
The query matches as a plain substring anywhere in the label, keywords, or hint. Case and accents don’t matter. There’s no fuzzy matching, on purpose: fuzzy search returns something for every query, so a typo gets you a confident list of wrong answers.
A query with several words matches when every word appears somewhere in the label, keywords or hint, in any order. file new finds New file, and copy clip finds Copy URL when one of its keywords is clipboard. Each word still has to appear as typed: new folder doesn’t find New file.
Ranking
Best first:
- the label starts with the query
- the label contains it (earlier positions rank higher)
- the label contains every word of the query, but not as one run
- a keyword contains the query, or the label and keywords contain every word between them
- the hint is needed to find the query or one of its words (earlier positions rank higher)
So a query typed as it appears in the label always beats the same words found scattered.
Groups are sorted by their best match, so the group holding the top hit comes first. With an empty query there is nothing to rank, and groups follow the group-order prop, or the order they first appear in commands.
A non-empty query draws at most 40 rows. Change that with max-results. The footer shows “first 40 of 112” when the list was capped.
Accents and typographic marks
Accented letters match their plain forms in both directions, so resume finds Résumé, and café finds Cafe. The highlight marks the label as written, accents included. Letters that aren’t an accented form of another letter, such as the æ in Encyclopædia, only match themselves.
Curly quotes, dashes and similar characters match their keyboard forms, so typing what's finds What’s new, and light - dark finds Light — dark.
Highlighting
Matched text is wrapped in <mark data-cmdk-highlight>. With several words, each one is marked where it first appears. Keywords only show when they matched, as small chips after the label, at most three per row.
If you render rows yourself, the CommandHighlight component draws the same marks from a row’s segments:
<CommandHighlight :segments="label" />
A custom matcher
Pass filter to replace matching and ranking. It returns null for no match, or a score where lower is better:
import type { FilterFn } from 'vue-cmdk-palette'
const filter: FilterFn = (command, needle) => (command.label.startsWith(needle) ? 0 : null)
Highlighting still uses the built-in substring match, so a filter that matches in other ways shows rows without marks.