Nuxt Swiftsearch
Getting Started

Declarative Transform

How Nuxt Swiftsearch compiles template widgets into connector arrays.

Nuxt Swiftsearch ships a Vite transform that converts declarative widget templates into the manual useAis* widget array expected by the SSR runtime.

What the transform does

  • Finds each <AisInstantSearch> root without an existing widgets binding.
  • Collects supported child widgets and <AisIndex> branches.
  • Injects a generated :widgets="..." computed binding.
  • Imports only the useAis* composables needed by that file.

Supported control flow

  • v-if, v-else-if, v-else branches are compiled to conditional array spreads.
  • <template v-if> wrappers are supported.
  • v-for on widget nodes is intentionally skipped (fallback to manual widgets for loops).

Ref/computed expression handling

Directive expressions used in props and conditions are normalized with automatic unref(...) support where needed.

This means ref-based props like :search-parameters="{ filters }" and branch conditions like v-if="showStats" work without manual .value access.

Automatic widget IDs

Every connector-backed widget that supports per-instance scoping receives an id:

  • when you set an explicit id="..." (or :id), that value is used and added to the corresponding useAis*({...}, id) call,
  • otherwise the transform auto-injects a deterministic swiftsearch-N-M id into the template markup so the runtime provide/inject path resolves cleanly.

This makes it safe to render multiple instances of the same widget (for example two <AisRefinementList attribute="brand" /> blocks) without their state leaking into each other.

Sharing one connector across multiple views

Reusing the same explicit id for a widget within an <AisInstantSearch> (or within an <AisIndex> scope) deduplicates the factory call. The transform emits a single useAis*({...}, "shared-id") and every component instance binds to that connector via inject:

<AisInstantSearch :configuration="configuration">
  <!-- "Top of page" hits and "bottom of page" hits share one connector -->
  <AisInfiniteHits id="hits-source" :show-previous="true" />

  <!-- ...other widgets... -->

  <AisInfiniteHits id="hits-source" />
</AisInstantSearch>

Dedupe is scoped per-<AisIndex>, so the same id reused inside a different index is treated as a separate connector.

Supported declarative widgets

AisAutocomplete, AisBreadcrumb, AisClearRefinements, AisConfigure, AisCurrentRefinements, AisDynamicWidgets, AisExperimentalConfigureRelatedItems, AisExperimentalDynamicWidgets, AisHierarchicalMenu, AisHits, AisHitsPerPage, AisIndex, AisInfiniteHits, AisMenu, AisMenuSelect, AisNumericMenu, AisPagination, AisPoweredBy, AisQueryRuleContext, AisQueryRuleCustomData, AisRangeInput, AisRatingMenu, AisRefinementList, AisRelevantSort, AisSearchBox, AisSortBy, AisStats, AisToggleRefinement, AisVoiceSearch.

When transform is skipped

  • <AisInstantSearch> already has :widgets.
  • Unsupported dynamic structure (for example widget v-for).
  • Files importing from vue-instantsearch directly.

In all skip cases, you can keep using manual :widgets composition.

Copyright © 2026