Declarative Transform
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 existingwidgetsbinding. - 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-elsebranches are compiled to conditional array spreads.<template v-if>wrappers are supported.v-foron 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 correspondinguseAis*({...}, id)call, - otherwise the transform auto-injects a deterministic
swiftsearch-N-Mid into the template markup so the runtimeprovide/injectpath 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-instantsearchdirectly.
In all skip cases, you can keep using manual :widgets composition.