Home > widget-integration > InstantSearchSelectors

InstantSearchSelectors class

Service for theme detection and selector management.

Technical Support teams can extend this service for custom themes:

Signature:

export declare class InstantSearchSelectors 

Example

window.boostWidgetIntegration.extend('InstantSearchSelectors', (InstantSearchSelectors) => {
  return class CustomSelectors extends InstantSearchSelectors {
    // Add custom theme detection
    protected getThemeConfigs() {
      return {
        ...super.getThemeConfigs(),
        myCustomTheme: {
          searchInputSelector: '.my-search-input',
          dialogSelector: '.my-search-modal'
        }
      };
    }
  };
});

Constructors

Constructor

Modifiers

Description

(constructor)(appService, positionService)

Constructs a new instance of the InstantSearchSelectors class

Properties

Property

Modifiers

Type

Description

appService

protected

AppService

boostClosedDialogs

protected

HTMLElement[]

Dialogs closed by .

Tracked by identity (not a data- marker) so can tell "a dialog we closed" apart from "a drawer the shopper opened", even after the theme reopens the same element later.

heldThemeScrollLock

protected

boolean

True when a dialog we closed left the theme's scroll lock engaged, so ISW is responsible for releasing it when it closes.

positionService

protected

PositionService

Methods

Method

Modifiers

Description

closeThemeDialogComponent(dialog)

protected

Ask the theme's own dialog component to close itself.

Horizon 2025+ releases its scroll lock only inside dialog-component.closeDialog(), and that method is gated on dialog.open — so calling the native dialog.close() first would make the release unreachable forever. Calling the component method keeps the theme's internal lock bookkeeping consistent (it may track lock sources per element, in which case removing the attribute alone is not enough).

Deliberately not awaited: Horizon's closeDialog() awaits an animation that may never run once the dialog leaves the top layer, so the returned promise can stay pending. is the fallback for that case.

closeThemeScrollLockDetails()

Close theme search panels built as <details scroll-lock> instead of a dialog.

Horizon locks scroll for these from a document-level toggle listener, so flipping open to false runs the theme's own unlockScroll() — no attribute surgery needed. Only panels that actually contain a search input are touched, so menu and cart drawers are left alone.

closeThemeSearchOverlays(customSelector)

Click all visible theme close buttons to dismiss overlays.

When ISW opens in **full-width** style, certain themes show their own search overlay/modal that conflicts with ISW. This method clicks all known close buttons to dismiss those overlays.

**Legacy**: Inline logic inside onOpenSuggestion() for full-width style **New**: Dedicated method on selectors service

detectThemeDialogs()

Detect open theme dialogs.

**1:1 port of legacy detectThemeDialogs().** Uses the same 3 hardcoded selectors — all of which already require [open] in the selector string, so only currently-open dialogs are returned.

detectThemeName()

protected

Detect theme name from various sources.

dismissSymmetrySearch()

Dismiss the Symmetry theme's search overlay.

Removes the show-search class from document.body.

findPredictiveSearchContainer(parent)

protected

Find a predictive search container inside a parent element.

Tries each selector from PREDICTIVE_SEARCH_SELECTORS in priority order.

getActiveContainer()

Resolve the ISW container the theme is actually displaying.

The mobile/desktop containers are toggled by the widget/theme CSS (media queries), whose breakpoint may not match the JS innerWidth < 991 heuristic. When that happens, the width guess resolves the *hidden* container and the visible panel is never unhidden (the first-open bug). Prefer the container that is genuinely on screen (offsetParent !== null); fall back to the width-based selector only when neither is resolvable yet (e.g. mid-init, before the containers are rendered).

getAllSearchInputs()

Get all search input elements.

**Legacy**: document.querySelectorAll('input[name="q"]...') **New**: Method using theme-specific selector

getCloseSearchThemeSelector(customSelector)

protected

Build the combined CSS selector for theme close buttons.

Merges the built-in close-button selectors (Prestige, Super Store, etc.) with an optional custom selector from generalSettings.closeSearchThemeSelector.

getContainerSelector(isMobile)

Get ISW container selector.

getFocusTrapRoot()

Resolve the element keyboard focus must stay inside while ISW is open.

Full-width layouts wrap the search bar *and* the results in .boost-sd__search-bar-wrapper — there WRAPPER_NAME is only an id — while dropdown layouts render it as a class. The lookup is scoped to the container of the current device: both containers live in the DOM and the inactive one is display: none.

Scoped via , not the width heuristic: resolving the hidden container yields no focusable elements and the trap goes dead.

getISWElement()

Get the ISW root element from the DOM.

getISWElementSelector()

Get the ISW root element selector.

getPredictiveSearchSelectors()

Get the predictive search selectors list.

Useful for extending or customizing which selectors are tried.

getSuggestionWrapper()

Get the suggestion wrapper element for the current device.

getThemeConfigs()

protected

Get theme configurations map. Override to add custom theme support.

**Legacy**: Hard-coded selectors scattered across index.js **New**: Centralized configuration object

getThemeSearchConfig()

Get theme-specific search configuration.

Detection priority: 1. Custom config from window.boostWidgetIntegrationConfig 2. Theme name from window.theme or Shopify theme settings 3. Selector presence detection 4. Default fallback

getWrapperSelector(isMobile)

Get ISW wrapper selector.

hasActiveThemeScrollLockSource()

protected

Check whether something other than the dialogs ISW closed still holds a theme scroll lock.

Sources considered: - any open dialog we did not close ourselves (cart drawer, menu modal) - <details scroll-lock open> elements, which Horizon locks on toggle

hideThemeDialog()

Hide theme search dialogs when ISW opens (full-width style).

**1:1 port of legacy hideThemeDialogWhenISWOpens().** Closes each open dialog and marks it with boostWasClosed so restoreThemeDialog() can identify which ones we closed.

Themes that lock page scroll from their dialog component (Horizon 2025+) get called first so their own unlockScroll() bookkeeping runs; the native close() still follows to remove the dialog from the browser top layer immediately (z-index conflict).

isFullWidthStyle(searchSettings)

Check if current style is full-width.

**Legacy**: isStyleFullWidth(context) function **New**: Method on selectors service

isMobileDevice()

Check if current device is mobile or tablet (≤ 991 px).

Matches the legacy isMobile(isTabletPortraitMax) threshold used by the old ISW code, which treats tablets up to 991 px as "mobile" for layout decisions (full-width style, container selector, etc.).

isSuggestionVisible()

Check whether the suggestion panel is currently visible.

The panel is considered visible when its wrapper element exists and does **not** have the boost-sd__g-hide CSS class.

**Legacy**: isSuggestionOpening(suggestionSelector) **New**: Method that resolves the wrapper internally

isSymmetrySearchOpen()

Check whether the Symmetry theme's search mode is active.

Symmetry adds a show-search class to document.body when its search overlay opens. When ISW closes it must remove this class first and delay the actual hide by 200 ms so the theme's CSS transition completes.

**Legacy**: document.body.classList.contains('show-search') inline check **New**: Dedicated predicate method

isThemeScrollLocked()

Check whether a theme scroll lock is currently engaged.

Looks for the scroll-lock attribute on <html> (Horizon 2025+) and on <body> (variants that lock on the body instead).

matchThemeFromConfig(customConfig)

protected

Match theme from custom config.

releaseThemeScrollLock()

Release a theme scroll lock left behind by a dialog ISW closed.

Only acts when ISW is the owner of the stale lock ( saw it survive) and nothing else still legitimately holds it — an open drawer or another modal keeps its lock untouched, see .

restoreThemeDialog()

Restore theme dialogs when ISW closes.

**1:1 port of legacy restoreThemeDialogWhenISWCloses().**

Note: In practice this is effectively a no-op for the full-width case. detectThemeDialogs() requires [open] in its selectors. After hideThemeDialog() calls dialog.close(), [open] is removed, so detectThemeDialogs() returns an empty array and the forEach never runs. The dialog stays closed until the user explicitly opens the theme search again.

For the dropdown/injection case where the dialog stayed open, the handleDialogIntegration observer closes it via moveISWBackToBody() when the theme itself fires the close event — not from here.

waitForISWElement(timeout)

Wait for the ISW root element (#bc-instant-search) to appear in the DOM.

Uses a MutationObserver on document.body so the caller can await the element even if it is injected asynchronously by the template renderer.

**Legacy**: waitForInstantSearchElement() standalone function **New**: Instance method on selectors service

waitForPredictiveSearchContainer(dialog, timeout)

Wait for a predictive search container inside a dialog element.

Shopify themes render predictive search components asynchronously inside their search dialogs. This method waits for one of the known selectors to become available so ISW can inject itself adjacent to the container.

**Legacy**: waitForPredictiveSearchContainer(dialog) standalone function **New**: Instance method on selectors service with timeout support