Search Experience — HawkSearch × Caster

Bring the #1 surface on the site under Caster — own the front door, skin the results
June 2026
View hero + autocomplete →
View query SERP →
Markdown source →

01TL;DR

Search drives 32.1% of all sessions — ~10× the browse landing. HawkSearch already powers it, but renders through Hawk's Handlebars templates plus a hawksearch-search-results web component that carries its own shadow DOM — so Caster's structural classes can't reach inside, and the result looks nothing like the redesigned site.

The fix splits by surface: own the entry surfaces as native Caster (hero search, autocomplete, machine lookup — calling Hawk's API), and skin the results surfaces in place (override Hawk's Handlebars templates + a .hawk-results-scoped Caster skin). Fix the searchRequest race as code hygiene.

PhaseSurfaceEffort
Phase 1 Front doorNative Caster hero search, autocomplete panel, and machine-lookup affordance, calling Hawk's suggest/search API. Fix the searchRequest null-reference race. Drop a token-level .hawk-results skin on the existing SERP.Medium — Caster front-end + one theme-JS bug fix
Phase 2 Reclaim SERPFull Hawk Handlebars-template override: results render Caster .product-cards; facets render the Caster accordion + removable chips + pagination. Compatibility-aware via compatible_models[].Higher — template override + content ops
Phase 3 Replace renderingSwap Hawk's Handlebars UI for its React/headless SDK as native Caster components (keep Hawk's API/index). Personalized ranking for signed-in fleets + AI/concept facets.Highest — Catalyst-replatform candidate

02Current state

Confirmed against the theme source — quasiobject/usa-clean (June 2026)

The integration is more controllable than first assumed — three corrections carry through the rest of this brief:

  1. Vendored, not CDN. hawksearch-handlebars-ui is committed into the theme at assets/js/hawksearch/ and webpack-built (env vars WEBPACK_HAWKSEARCH_*). Entry point: assets/js/hawksearch/index.js, run from app.js.
  2. The theme already overrides Hawk's templates. index.js registers theme-owned Handlebars templates for every major component — search-results, search-results-item / -list, facets-list, autocomplete, search-field, sorting, page-size (in assets/js/hawksearch/templates/*.hbs). The header search is <hawksearch-search-field> (native BC quick-search is commented out). We already control the markup.
  3. Shadow DOM is not a blocker — there's a sanctioned injection point. Hawk renders into hawksearch-* web components (some with shadow DOM), but the init passes css: { customStyles: 'hawksearch-custom-styles' }, and hawksearch-custom-styles.html is a <template> whose <style> opens :host, :root { --hawksearch-color-accent: #00209F; … } — i.e. it is adopted inside the shadow roots. Any CSS placed there, Caster's included, reaches inside the encapsulation.

Net: bringing search under Caster is concentrated work in two places — the .hbs templates (markup → Caster classes) and hawksearch-custom-styles (CSS → Caster tokens/components) — plus the searchRequest null-guard. It is not a fight against encapsulation.

USA Clean's /search is powered by HawkSearch (Bridgeline Digital), via the vendored @bridgeline-digital/hawksearch-handlebars-ui library (committed in the theme, webpack-built) wired into the BigCommerce Stencil theme. It renders through theme-owned Handlebars templates mounted inside a tree of hawksearch-* web components — the /search page mounts <hawksearch-search-results>, which contains hawksearch-facets-list, hawksearch-search-results-list, hawksearch-autocomplete, hawksearch-sorting, hawksearch-pagination, and the theme's own pagination-summary element (which does carry its own shadow DOM).

What's wrong today:

  • It's visually foreign. Hawk injects its own component CSS late in the page (its own .button, its own card markup). The Caster site stops at the edge of search results and a different design language takes over. The stencil-integration doc already flags this and prescribes .hawk-results .btn { … } scoping.
  • A known race condition blanks the grid. The theme's partSearchLinks reads HawkSearch.searchRequest before async init resolves (Cannot read properties of null, 251 sessions). On a cold /search load Hawk counts 268,271 results but renders zero. Limited real-world impact, but a real bug.
  • The front door is generic. The homepage leads with browse CTAs, not search — despite the 9.8× search:browse ratio. Autocomplete is Hawk's stock suggestions, not tuned to part number / brand / machine model.
  • There's no machine-lookup intercept. The dominant job is "I have a Tennant T5, I need its parts," but nothing captures a brand+model at the point of search. Hawk has the data; the UI doesn't expose it.
  • Hawk contributes to CLS (0.29, above Google's 0.25 "poor" threshold) by injecting results after first paint.

Search is already the navigation; the redesign should make search feel like the rest of the site and meet the brand→model mental model head-on.

03References

Grainger

Best-in-class industrial autocomplete: as you type, the panel splits into suggested terms, categories, and product previews with thumbnails + price. The model to emulate for the Caster autocomplete panel — grouped, scannable, keyboard-navigable.

McMaster-Carr

The gold standard for industrial faceted search: instant results, server-fast facets, no full-page reload, dense scannable rows. Sets the bar for what "reclaiming the SERP" should feel like — Hawk's engine can approach this; its stock UI does not.

Sweepscrub

Parts search scoped to cleaning equipment by brand→model. Same catalog shape as USA Clean; their search is a flat filtered list with no machine intercept — the gap our machine-lookup affordance closes.

Tennant.com (OEM)

Model-scoped search routes to a spec/doc page but has no parts-purchase path. Confirms the brand→model intent is universal; USA Clean's opportunity is to be the rich, buyable search destination for every machine.

Baymard Institute — B2B search & autocomplete

B2B research shows part-number / SKU search and "scoped search" (search within a machine's compatible parts) are patterns buyers expect. Autocomplete that previews products, not just query strings, measurably reduces abandonment.

The search-app comparison class — Algolia / Klevu / Searchspring

The peer set for HawkSearch. Relevant only to confirm that swapping the engine is not warranted (see shortlist): Hawk's relevance/merchandising/facets are competitive; the deficiency is the front-end skin, which is ours to fix.

04What BC Stencil gives us

  • HawkSearch is already integrated and paid for. The engine (index, relevance, facets, synonyms, "did you mean," keyword redirects, recommendations, merchandising/pinning, analytics) is configured in the Hawk dashboard and serves the /search template. No engine work needed.
  • Hawk's Handlebars UI is template-overridable. @bridgeline-digital/hawksearch-handlebars-ui renders from Handlebars partials we can override, and accepts supplemental CSS. This is the hook for the Phase 2 Caster skin.
  • Hawk's suggest/search API is callable directly. The autocomplete and machine-lookup surfaces (Phase 1) can query Hawk's API and render our own Caster markup — we don't have to accept Hawk's stock suggestion UI.
  • /search Stencil template overridetemplates/pages/search.html is ours to control for the page chrome around Hawk's component.
  • Product custom field compatible_models[] (the same field that powers model-landing) lets results and facets be compatibility-aware — "parts that fit your Tennant T500e" as a Hawk facet or scoped search.
  • Storefront API for supplemental product data the result cards need (stock, price tiers).

05Stencil limitations

  • Shadow DOM is encapsulated, but the theme has a sanctioned styling channel. Global components.css and a .hawk-results .btn {…} scope do not reach inside Hawk's hawksearch-* components. The path that does work is already wired: author CSS into the hawksearch-custom-styles template (adopted into the shadow roots) and edit the .hbs templates for structure. The real cost is that Caster's search CSS lives in that Hawk-specific template, parallel to components.css — not that styling is impossible.
  • Two templating systems to maintain. Search markup lives in assets/js/hawksearch/templates/*.hbs, separate from Stencil's page templates. Already true today; porting to Caster edits an existing system rather than adding one.
  • Bespoke autocomplete groups need API-level work. search-autocomplete.hbs already groups suggested-queries / categories / content / products — restyling those is template + CSS work. Groups Hawk's response doesn't provide (e.g. recent / saved machines for signed-in fleets) require joining the account to the suggest call — custom front-end beyond a restyle.
  • No machine-lookup intercept in stock Hawk. Brand+model → scoped parts is a custom affordance on top of Hawk's search API.
  • The searchRequest race is theme-JS, not Hawk. Confirmed at assets/js/hawksearch/index.js:173, inside the theme's pagination-summary shadow element: if (HawkSearch.searchRequest.query) runs before searchRequest resolves on cold loads. Fix = HawkSearch.searchRequest?.query. (That heading is also hard-coded font-size:25px; font-weight:700 inline — a Caster-token opportunity.)
  • CLS from late injection. Reserving space for <hawksearch-search-results> (min-height / skeleton) is a theme-template fix.

06App marketplace shortlist

The usual "native vs. app vs. custom" table is inverted here: HawkSearch is the app, and it's already deployed. The real decision is what to do with its front end.

OptionWhat it isVerdict
Skin Hawk in placeEdit the theme's .hbs templates + the shadow-injected hawksearch-custom-styles. The theme already owns both — port them to Caster. Already the architecture
Own the entry surfaces as native CasterCustom Caster front end (hero, autocomplete, machine lookup) on Hawk's suggest/search API. Phase 1 path
Swap the search engine (Klevu / Searchspring / Algolia)Replace HawkSearch with a different search app.Skip — engine isn't the problem
BC native faceted searchDrop Hawk, use Stencil's stock faceted search.Skip — capability downgrade
Replace Hawk's rendering (React/headless SDK)Keep Hawk's API/index; render results as native Caster React components. Phase 3 / Catalyst
Amortization note (Rule #3)

Swapping engines carries a recurring new-subscription cost plus a large migration; the front-end skin is a one-time build against an engine we already pay for. The custom entry surfaces are a one-time build whose payback is immediate (the front door of a 32%-of-sessions surface) — no subscription competes with them.

07Caster impact

New patterns introduced inline in v2/ first (Rule #7), promoted to Caster when a second consumer arrives:

  • .search-autocomplete — combobox/suggestions panel: grouped sections (products with thumb+price, categories, popular searches, recent machines), keyboard-navigable, built on the existing dropdown.* tokens.
  • .search-hero — search-dominant hero block with model-aware placeholder and inline scope chips.
  • .facet-group — collapsible accordion filter group (the gap between Caster's .checkbox and a real facet rail).
  • .filter-chip — removable applied-filter chip (× to clear) — a .pill variant with a remove affordance.
  • .pagination — page controls / load-more (Caster has none today).
  • .input--search — input with a leading magnifier icon (Caster's .input has no leading-icon slot).
  • .facet-drawer — off-canvas mobile facet panel (37% of traffic is mobile).
  • .hawk-results skin — the scoping convention from stencil-integration.html: .hawk-results { --caster-…: … } to pass tokens across the shadow boundary, plus .hawk-results .btn { … } for non-encapsulated overrides.

Reused as-is: .input / .input-group, .product-card, .pill, .stock-badge, .checkbox, .tabs, .container, .site-header__search, .machine-card.

Downstream impact: the autocomplete panel and .input--search also serve the global header search on every page; the facet patterns serve any future filtered listing. These graduate to Caster quickly because they have multiple consumers by design.

08Phased recommendation

Phase 1 — Own the front door

Ship the three entry surfaces as native Caster, calling Hawk's API; fix the race; stop the SERP from clashing.

  1. Elevated hero search (roadmap #8) — search input as the dominant homepage element, model-aware placeholder, optional scope chips (All / Parts / Machines).
  2. Caster autocomplete panel — grouped suggestions: products (thumb + SKU + price + stock), categories, popular searches, recent/saved machines. Full keyboard + ARIA combobox semantics.
  3. Machine-lookup affordance — brand-select + model/serial entry routing to a compatibility-scoped result set (and the model-landing page when one exists). Shares the megamenu "Find by machine" story.
  4. Bug fix — guard HawkSearch.searchRequest / move partSearchLinks to the hawksearch:search-complete event; reserve result-area height to cut CLS.
  5. Token-level .hawk-results skin — pass --caster-* into Hawk's shadow DOM so the SERP adopts Caster color/type immediately.

What "winning" looks like: higher search-initiation rate from the homepage, climbing autocomplete-selection rate, machine-lookup usage, and the cold-load blank-grid error going to zero.

Phase 2 — Reclaim the SERP

Override Hawk's Handlebars templates so results and facets render as Caster:

  • Result cards → .product-card (with compatibility note when compatible_models[] matches the user's fleet).
  • Facet rail → .facet-group accordion + .filter-chip applied-filter row + .pagination.
  • Mobile → .facet-drawer.
  • Compatibility-aware results: a "fits my equipment" Hawk facet driven by compatible_models[].

Trigger: Phase 1 is live and the token skin proves the SERP is the remaining seam; merch has begun populating compatible_models[] (shared with model-landing Phase 2).

Phase 3 — Replace the rendering

Swap Hawk's Handlebars UI for its React/headless SDK, rendered as native Caster components (Hawk's API/index unchanged). Adds personalized result ranking for signed-in fleets ("parts your fleet has bought for this model first") and AI/concept facets.

Catalyst-replatform candidate — see below.

09Implementation notes

Where the Caster work lands (confirmed file map)

The whole search redesign is two files of theme work plus a one-line fix:

  • Markup → Caster classes/structure: assets/js/hawksearch/templates/*.hbssearch-results.hbs (SERP layout), search-results-item.hbs (result card → .product-card), search-facets-list.hbs (facet rail → accordion), search-autocomplete.hbs (grouped panel), search-field.hbs (input).
  • CSS → Caster tokens/components: templates/usac/components/hawksearch-custom-styles.html — the <style> adopted into the shadow roots. Bridge --hawksearch-* to Caster values (e.g. --hawksearch-color-accent: var(--caster-color-brand-default)) and add the .product-card / facet / autocomplete CSS here (not in global components.css, which can't reach the shadow DOM). Pull Caster tokens in via @import or by inlining the token layer into this template.
  • Bug fix: assets/js/hawksearch/index.js:173HawkSearch.searchRequest?.query.
  • The header search (<hawksearch-search-field>) and autocomplete are the same component pair site-wide, so a single restyle covers the header and any hero placement.

The searchRequest fix

Null-guard HawkSearch.searchRequest?.query in partSearchLinks, or move the call into a hawksearch:search-complete listener so it never runs before async init. Reserve the result container's min-height to cut the post-paint shift.

Autocomplete accessibility

ARIA combobox pattern: role="combobox" input with aria-expanded / aria-controls, role="listbox" panel, aria-activedescendant tracking the highlighted option; full keyboard support (↑/↓, Enter, Esc, Home/End); group headings are non-focusable labels. Debounce the suggest call; show a loading affordance; handle zero-suggestions gracefully.

Compatibility data

Compatibility-aware results/facets read the product compatible_models[] custom field — the same data investment as model-landing Phase 2. Tagging the ~12k-part catalog is the shared content-ops cost; sequence it once for both features.

Analytics

  • Search-initiation rate (homepage hero) and autocomplete-selection rate.
  • Zero-result query rate (feeds Hawk synonym/redirect tuning in the dashboard).
  • Machine-lookup usage and its conversion vs. plain search.
  • Search → result-click → PDP → cart funnel; cold-load error count (should hit zero post-fix).

Mobile behavior

Search pinned to the top bar; autocomplete panel full-width below it; facets collapse into the .facet-drawer off-canvas panel (37% of traffic is mobile, and mobile users are disproportionately forced into search because the nav fails at 375px — roadmap #10).

10Catalyst / replatform candidacy

Phase 1 + Phase 2 ship in Stencil. Native Caster entry surfaces calling Hawk's API, a theme-JS bug fix, and a Handlebars-template override are all Stencil-native work. No replatform needed to bring search under Caster.

Phase 3 is the Catalyst case. HawkSearch ships React/headless SDKs that fit a Catalyst storefront far better than its Handlebars UI fits Stencil — rendering Hawk results as first-class React components eliminates the shadow-DOM friction entirely, and personalized server-side ranking (fleet-aware order on first paint) is exactly what Stencil struggles to do without jitter. Combined with the headless roadmap and model-landing Phase 3 personalization, search rendering is a natural anchor for the replatform — but not a reason to replatform on its own. Skinning Hawk in Stencil (Phases 1–2) buys visual consistency now; Phase 3 waits for the personalization + headless forcing function.

11Sources