Skip to content

feat(ui): add SearchInput with clear button and Escape-to-clear (#377) - #418

Merged
TheVicky1 merged 2 commits into
TheVicky1:mainfrom
ZeroElemental:feat/search-input-clear
Oct 6, 2026
Merged

TheVicky1 merged 2 commits into
TheVicky1:mainfrom
ZeroElemental:feat/search-input-clear

Conversation

@ZeroElemental

Copy link
Copy Markdown
Contributor

1. Related Issue

Closes #377


2. Summary of Changes

Adds a reusable SearchInput (src/components/ui/search-input.tsx), exported from src/components/ui/index.ts.

  • A controlled field (value, onChange(value: string)) with a search icon.
  • An "X" clear button (aria-label="Clear search") that appears only when the query isn't empty.
  • Clicking X or pressing Escape resets the query to "".
  • Pressing Escape when the field is already empty does nothing, so parent Escape handlers (modals, the command palette) still get the key.
  • Passes through any other input props, including a caller's own onKeyDown.

Also contains a small fix to the shared Input component (separate commit). The input's backdrop-blur creates a stacking context that was painted over the absolutely positioned leftIcon/rightIcon wrappers, so the icons were invisible. Adding z-10 to the wrappers fixes it. No existing caller used these props, so nothing else changes visually.


3. Motivation & Context

Gives search fields a quick, keyboard-friendly way to reset the query.


4. Implementation Details

  • Built on the existing Input primitive, with the Search/X icons from lucide-react.
  • Uses type="search" and hides the browser's native cancel button, so there's only one clear control.
  • Tests are in tests/search-input.test.ts (node:test with SSR markup; the component is stateless, so its handlers are called directly). The 7 tests cover:
    • the button hidden or shown depending on the value
    • click-to-clear
    • Escape clearing the field and calling preventDefault
    • Escape on an empty field passing through
    • other keys not clearing, and a caller's onKeyDown still being called
    • typed text being forwarded to onChange

5. Testing & Local Validation

  • npm run lint — ESLint passed with 0 errors
  • npx tsc --noEmit — TypeScript strict check passed with 0 errors
  • npm test (or node scratch/run-tests.mjs) — 67/67 suites passed
  • npm run test:file -- search-input — 7/7 tests passed
  • node scratch/secret-scan.mjs — Zero secrets or sensitive credentials detected
  • npm run build — Production build succeeded without errors

Also checked manually in the browser: the search icon and X are visible, X appears only when there's text, and Escape clears the field.


6. UI & Visual Changes

  • UI modifications included:
    • Tested responsive scaling on mobile (375px), tablet (768px), and desktop (1280px+)
    • Adhered to the luxury Obsidian & Gold palette (docs/DESIGN_SYSTEM.md)
    • Verified visible focus states and contrast ratios (WCAG AA)

7. Database & Security Impact

  • No database or security-sensitive changes

8. Documentation Impact

  • Documentation updates not required for this change

9. Contributor Quality Checklist

  • 🌱 Micro-Contribution Fast-Path: This is a targeted Good First Issue / 5–30 minute micro-change (single file, verified locally).
  • My PR has a single, focused scope (avoiding unrelated formatting or refactoring).
  • I have read and followed PACT's Contributing Guide.
  • I confirm that zero secrets, API keys, private tokens, or .env.local files are included in this PR.
  • My branch was created from the latest upstream/main with an appropriate prefix (e.g., feat/, fix/, docs/, ui/).
  • My commits follow the Conventional Commits format (type(scope): description).
  • I have linked the target issue in Section 1 above.
  • I have reviewed my own git diff to ensure no stray files or debugging artifacts were committed.

10. Reviewer Notes

The Input icon fix is a separate commit (fix(ui): keep Input icons above the blurred input background), so it can be dropped or split out if you'd prefer.

…icky1#377)

Controlled search field built on Input. Shows an "X" clear button only
when the query is non-empty; clicking it or pressing Escape resets the
query. Escape on an empty field is left alone so parent handlers
(modals, palettes) still receive it.
The input's backdrop-blur creates a stacking context painted after the
absolutely positioned icon wrappers, hiding leftIcon/rightIcon. Lift
the wrappers with z-10 so SearchInput's search icon is visible.
@vercel

vercel Bot commented Oct 6, 2026

Copy link
Copy Markdown

@ZeroElemental is attempting to deploy a commit to the Vicky's projects Team on Vercel.

A member of the Team first needs to authorize it.

@TheVicky1
TheVicky1 merged commit 93b4ec7 into TheVicky1:main Oct 6, 2026
3 of 4 checks passed
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.

[UX] Implement Quick Search Clear Button with Keyboard Escape Listener

2 participants