An on-site search overlay and autocomplete that attaches to a storefront's own search box with one script. Typo tolerance, facets, synonyms, redirects and ten layout presets, configured per brand without code. Live on 271 brands.
271brands live
10presets: 4 shells × 16 blocks
~9klines across v2 and SearchKit
0dependencies at runtime
Try it
Search an invented store
Click the search box or press / inside the demo. Try a typo like "lnen", a synonym like "tee", or switch presets.
The interactive search needs JavaScript. It shows a storefront whose search box opens an overlay with autocomplete, category chips, sorting, facets, typo correction and ten SearchKit layout presets and the classic V2 overlay over a synthetic catalogue.
Same client-side behaviour as production, with an in-memory catalogue and simulated network latency in place of the search service.
Problem
The old search widget was styled by hand for each brand, had no typo tolerance and no filters, and brands kept sending screenshots of competitors' search.
Every storefront has a different header, a different search input and its own CSS reset. The backend search service returns ranked products and categories but does not handle typos or narrowing by attribute. A replacement had to work on hundreds of sites without per-site code.
My role
I wrote Search V2 and its preset engine, SearchKit, as the only author, and the tooling used for the bulk rollout. The search service behind it is an existing Lucene-based endpoint I integrated with.
One IIFE bundle built with esbuild that creates its own DOM and CSS
Render + trackPreset shell and blocks, search and click events.
Violet tint: parts I wrote.
Engineering decisions
What was hard and what I did
CSS that survives 271 other stylesheets
I first moved the base styles into @layer. Brands' unlayered resets beat layered rules, so I rolled it back and went with prefix-scoped selectors that out-rank a brand reset without !important everywhere. A cascade test page has to pass 8 of 8 before release.
No stale results
Every keystroke aborts the previous request with an AbortController, and a sequence guard drops anything that arrives late. Loading is a small state machine: skeleton after 550 ms, a "slow" notice at 3 s, timeout at 10 s.
Turkish text, done properly
Folding treats dotless ı as its own letter, repairs mis-decoded characters without decoding twice, and parses prices like 31.000,00 TL correctly. A wrong parse once showed 31 instead of 31,000.
Typos the backend doesn't catch
When a query returns nothing, the client compares it with a vocabulary built from product titles and offers "did you mean", then falls back to recommended products instead of an empty page.
Keyboard and screen readers
The input is an ARIA combobox with a listbox, results support arrow keys, / focuses search, focus is trapped while the overlay is open and returns on close, and reduced motion turns off movement.
A field guide for "it won't open"
On real sites the usual causes were dead selectors, consent banners holding scripts back, other vendors' search scripts and cached config. I wrote them down with fixes so support could solve most cases without me.
Before V2
Search V2 grew out of earlier work on a searchandising results page: a config-driven script that renders the full results page after a search, with category, banner and sorting rules per brand. It taught me where per-brand code goes wrong, which is why V2 pushed everything brand-specific into configuration.
Have a problem worth solving?Let's make it reliable