Help page search input is non-functional: setSearchQuery wired but searchQuery never read by any filter — typing does nothing #144

Closed
opened 2026-10-03 04:07:31 +00:00 by Mark · 1 comment
Owner

Finding

The Help page has a search input at src/pages/Help.tsx:341 with placeholder="Search topics, stitch types, error messages...". The state is set via setSearchQuery, but the searchQuery value is never read to filter any content. The input is purely decorative — typing into it does nothing.

Where

  • State declared: src/pages/Help.tsx:341 — const [searchQuery, setSearchQuery] = useState('')
  • Input renders: src/pages/Help.tsx:393-394
  • Where it's read: nowhere. searchQuery is set on change and never referenced in any filter, search, or render.

Verified by: grep -rn 'searchQuery' src/pages/Help.tsx returns 3 references (the useState declaration, the input value binding, the onChange handler). No reference in a .filter(), .find(), .includes(), or any conditional render.

Suggested fix shape

Make the search input functional:

  1. Filter the FAQ items: when searchQuery.trim() is non-empty, filter faqItems by case-insensitive match on q (question) or a (answer).
  2. Filter the stitch type documentation: same, against stitchTypes.
  3. Filter the compatibility table: same, against machine or status.
  4. Show a "No results" state when the filter matches nothing.

The simplest implementation: derive a single filteredSections object that contains the filtered lists of each section, then render those.

const q = searchQuery.trim().toLowerCase();
const filteredFaq = q ? faqItems.filter(f => f.q.toLowerCase().includes(q) || f.a.toLowerCase().includes(q)) : faqItems;
const filteredStitchTypes = q ? stitchTypes.filter(s => s.name.toLowerCase().includes(q) || s.bestFor.toLowerCase().includes(q)) : stitchTypes;
// etc.

The placeholder promises "topics, stitch types, error messages" — the implementation should cover at least topics and stitch types. Error messages are a stretch (the help page doesn't have a structured error-message section), so skip those.

Severity

Medium. A user looking for "how do I export" types "export" and gets no feedback. Either the input does nothing (current state) or the page scrolls to matches. Without a filter, the input is a UI lie.

Discovered by

Gap analysis (2026-10-02) of Help page interactive elements.

  • The Help page's search input was likely added as a UI promise without a follow-up implementation. Same family as the "Watch Demo" hero button (#81) that was fixed in round 1 to point to /help.
## Finding The Help page has a search input at `src/pages/Help.tsx:341` with `placeholder="Search topics, stitch types, error messages..."`. The state is set via `setSearchQuery`, but **the searchQuery value is never read to filter any content**. The input is purely decorative — typing into it does nothing. ## Where - State declared: `src/pages/Help.tsx:341` — `const [searchQuery, setSearchQuery] = useState('')` - Input renders: `src/pages/Help.tsx:393-394` - Where it's read: nowhere. `searchQuery` is set on change and never referenced in any filter, search, or render. Verified by: `grep -rn 'searchQuery' src/pages/Help.tsx` returns 3 references (the useState declaration, the input value binding, the onChange handler). No reference in a `.filter()`, `.find()`, `.includes()`, or any conditional render. ## Suggested fix shape Make the search input functional: 1. **Filter the FAQ items**: when `searchQuery.trim()` is non-empty, filter `faqItems` by case-insensitive match on `q` (question) or `a` (answer). 2. **Filter the stitch type documentation**: same, against `stitchTypes`. 3. **Filter the compatibility table**: same, against `machine` or `status`. 4. **Show a "No results" state** when the filter matches nothing. The simplest implementation: derive a single `filteredSections` object that contains the filtered lists of each section, then render those. ```ts const q = searchQuery.trim().toLowerCase(); const filteredFaq = q ? faqItems.filter(f => f.q.toLowerCase().includes(q) || f.a.toLowerCase().includes(q)) : faqItems; const filteredStitchTypes = q ? stitchTypes.filter(s => s.name.toLowerCase().includes(q) || s.bestFor.toLowerCase().includes(q)) : stitchTypes; // etc. ``` The placeholder promises "topics, stitch types, error messages" — the implementation should cover at least topics and stitch types. Error messages are a stretch (the help page doesn't have a structured error-message section), so skip those. ## Severity Medium. A user looking for "how do I export" types "export" and gets no feedback. Either the input does nothing (current state) or the page scrolls to matches. Without a filter, the input is a UI lie. ## Discovered by Gap analysis (2026-10-02) of Help page interactive elements. ## Related - The Help page's search input was likely added as a UI promise without a follow-up implementation. Same family as the "Watch Demo" hero button (#81) that was fixed in round 1 to point to `/help`.
Author
Owner

Fixed in commit f29cfd1 on main.

The Help page search input now actually filters:

  • FAQ accordion: matches against question and answer text
  • Stitch types grid: matches against stitch name and bestFor description
  • Compatibility table: matches against machine name and status

When the query matches nothing across all three sections, a No matches for "<query>". banner appears under the search input.

Added 5 regression tests in src/pages/Help.test.tsx covering each filter path, the no-results state, and clearing the input.

Fixed in commit f29cfd1 on main. The Help page search input now actually filters: - FAQ accordion: matches against question and answer text - Stitch types grid: matches against stitch name and bestFor description - Compatibility table: matches against machine name and status When the query matches nothing across all three sections, a `No matches for "<query>".` banner appears under the search input. Added 5 regression tests in `src/pages/Help.test.tsx` covering each filter path, the no-results state, and clearing the input.
Mark closed this issue 2026-10-03 06:09:07 +00:00
Sign in to join this conversation.
No description provided.