Skip to Content
HelpHelp Improvement 3 — Search Improvements

Help Improvement 3 — Search Improvements

Status: [To Build]

Purpose: The current help search uses plain substring matching — “bolg” finds nothing, results show no context about why they matched, and there is no keyboard shortcut to reach the search box. Three targeted fixes address this.


Fix A — Fuzzy Search with Fuse.js

Replace the text.includes(query) filter with Fuse.js  — a lightweight, zero-dependency fuzzy search library.

Why Fuse.js over alternatives

OptionSizeFuzzyRankingAlready in project
String.includes (current)0NoNoYes
Fuse.js24 kBYesYesNo — add once
Minisearch29 kBPartialYesNo
Flexsearch40 kBNoYesNo

Fuse.js gives fuzzy matching and result ranking with a single npm add fuse.js.

Implementation

// packages/ui/src/HelpCenter.tsx import Fuse from "fuse.js"; // Build Fuse index once on mount const fuse = useMemo(() => new Fuse(pages, { keys: [ { name: "title", weight: 0.4 }, { name: "description", weight: 0.3 }, { name: "tags", weight: 0.2 }, { name: "categoryLabel", weight: 0.1 }, ], threshold: 0.35, // 0 = exact, 1 = match anything; 0.35 is forgiving but not noise includeScore: true, includeMatches: true, // needed for highlighting (Fix B) }), [pages]); // Replace the current filter: const filtered = useMemo(() => { const q = query.trim(); if (!q) return null; return fuse.search(q).map(r => ({ page: r.item, matches: r.matches })); }, [query, fuse]);

Fix B — Match Highlighting in Results

Currently search results show the topic title and description with no indication of what matched. Highlighting the matching substrings makes results scannable.

HighlightText component

// packages/ui/src/HighlightText.tsx interface HighlightTextProps { text: string; indices?: readonly [number, number][]; // Fuse.js match indices className?: string; } export function HighlightText({ text, indices, className }: HighlightTextProps) { if (!indices?.length) return <span className={className}>{text}</span>; const parts: React.ReactNode[] = []; let last = 0; for (const [start, end] of indices) { if (start > last) parts.push(text.slice(last, start)); parts.push( <mark key={start} className="bg-yellow-100 dark:bg-yellow-900 text-inherit rounded-sm px-0.5"> {text.slice(start, end + 1)} </mark> ); last = end + 1; } if (last < text.length) parts.push(text.slice(last)); return <span className={className}>{parts}</span>; }

In the search result cards, replace plain {page.title} and {page.description} with:

<HighlightText text={page.title} indices={matches?.find(m => m.key === "title")?.indices} /> <HighlightText text={page.description} indices={matches?.find(m => m.key === "description")?.indices} className="text-sm text-muted-foreground" />

Fix C — Keyboard Focus Shortcut

When the user presses ? anywhere on the Help Center page, focus jumps to the search input. This is a common convention for search-heavy pages (GitHub, Linear, etc.).

Note: Ctrl+K is already taken by the global Typesense search modal — use ? (question mark) instead, which is natural for a help page.

// In HelpCenter component const inputRef = useRef<HTMLInputElement>(null); useEffect(() => { function handleKey(e: KeyboardEvent) { // Don't steal focus when typing in another input/textarea if (e.key === "?" && e.target === document.body) { e.preventDefault(); inputRef.current?.focus(); } } document.addEventListener("keydown", handleKey); return () => document.removeEventListener("keydown", handleKey); }, []);

Add a subtle keyboard hint next to the search placeholder:

<div className="relative"> <Search className="absolute left-3 top-1/2 -translate-y-1/2 w-4 h-4 text-muted-foreground" /> <input ref={inputRef} placeholder="Search help topics…" className="pl-9 pr-16 ..." /> <kbd className="absolute right-3 top-1/2 -translate-y-1/2 text-xs text-muted-foreground border rounded px-1.5 py-0.5 font-mono hidden sm:inline">?</kbd> </div>

Affected Files

FileChange
packages/ui/package.jsonAdd fuse.js dependency
packages/ui/src/HelpCenter.tsxReplace substring filter with Fuse.js; pass match metadata to cards
packages/ui/src/HighlightText.tsxNew component
packages/ui/src/index.tsExport HighlightText

© 2026 Leadmetrics — Internal use only