-
Notifications
You must be signed in to change notification settings - Fork 0
Search Engine
ABCrimson edited this page Mar 11, 2026
·
2 revisions
The built-in TypeScript scorer uses fuzzy matching with these scoring factors:
- Exact match — Highest score when query matches item value exactly
- Prefix match — High score for matches at the start of words
- Consecutive characters — Bonus for adjacent character matches
- Word boundary bonus — Higher scores when matches align with word boundaries (spaces, hyphens, camelCase)
- Position penalty — Matches earlier in the string score higher
Score aggregation uses Math.sumPrecise (ES2026) for accurate floating-point summation.
When the user types additional characters (e.g., "ap" → "app"), the engine only re-scores items that matched the previous query, using Set.difference for efficient candidate pruning.
// First search: scores all 10K items engine.search('a', items); // → 6,000 results // Incremental: only re-scores the 6,000 matches, not all 10K engine.search('ap', items); // → 2,000 results (from 6K candidates) engine.search('app', items); // → 500 results (from 2K candidates)
Provide a custom scorer function:
import { createSearchEngine, type ScorerFn } from 'modern-cmdk'; const myScorer: ScorerFn = (query, item) => { if (item.value.toLowerCase().includes(query.toLowerCase())) { return { id: item.id, score: 1, matches: [] }; } return null; // No match }; using engine = createSearchEngine({ scorer: myScorer });
For datasets > 10K items, use the WASM trigram index:
import { createWasmSearchEngine } from 'modern-cmdk-search-wasm'; await using engine = await createWasmSearchEngine(); engine.index(items); const results = engine.search('query', items).toArray();
See WASM Search for details.
| Operation | 1K Items | 10K Items | 100K Items |
|---|---|---|---|
| JS scorer (full pipeline) | ~0.5ms | ~5ms | ~50ms |
| JS scorer (incremental) | ~0.2ms | ~2ms | ~20ms |
| WASM scorer | ~0.1ms | ~0.8ms | ~3ms |