Examples
Manual Widgets Mode
Keep legacy `:widgets` composition while using Swiftsearch components.
This pattern is used in the playground /search page to verify backwards compatibility.
pages/search.vue
<template>
<AisInstantSearch :configuration="configuration" :widgets="widgets" instance-key="search">
<AisSearchBox />
<AisToggleRefinement attribute="free_shipping" />
<AisRefinementList attribute="brand" searchable />
<AisSortBy />
<AisStats />
<AisInfiniteHits />
<AisIndex index="airbnb">
<AisInfiniteHits />
</AisIndex>
</AisInstantSearch>
</template>
<script setup lang="ts">
import { algoliasearch } from "algoliasearch";
import { singleIndex as singleIndexMapping } from "instantsearch.js/es/lib/stateMappings";
const client = algoliasearch("latency", "6be0576ff61c053d5f9a3225e2a90f76");
const algoliaRouter = useAisRouter();
const airbnbIndex = useAisIndex({ indexName: "airbnb" });
airbnbIndex.addWidgets([useAisInfiniteHits({})]);
const widgets = computed(() => [
useAisSortBy({
items: [
{ value: "instant_search", label: "Default" },
{ value: "instant_search_price_asc", label: "Price asc." },
{ value: "instant_search_price_desc", label: "Price desc." },
],
}),
useAisStats({}),
useAisInfiniteHits({ showPrevious: true }),
useAisRefinementList({ attribute: "brand", showMore: true }, "brand-search"),
useAisToggleRefinement({ attribute: "free_shipping" }),
useAisSearchBox({}),
airbnbIndex,
]);
const configuration = {
indexName: "instant_search",
searchClient: client,
routing: {
router: algoliaRouter.value.router,
stateMapping: singleIndexMapping("instant_search"),
},
};
</script>
Use this mode for dynamic widget generation, advanced branching, or when migrating incrementally.
Sharing a connector across components
When two components target the same connector and you want them to share state, register the composable with a widgetId and pass that same id to each component:
<template>
<AisInstantSearch :configuration="configuration" :widgets="widgets">
<!-- Both render against the same brand-search connector -->
<AisRefinementList attribute="brand" id="brand-search" />
<AisRefinementList attribute="brand" id="brand-search" />
</AisInstantSearch>
</template>
<script setup lang="ts">
const widgets = computed(() => [
useAisRefinementList({ attribute: "brand", showMore: true }, "brand-search"),
]);
</script>
Without a widgetId (default)
If you skip the second argument to useAis* and leave the component id unset, every instance still works — components fall back to a composable-level render-state map keyed by attribute. This means controls like toggleShowMore() and searchForItems() keep re-rendering the list inline (this is the path covered by the <AisRefinementList> regression tests):
<script setup lang="ts">
const widgets = computed(() => [
useAisRefinementList({ attribute: "brand", showMore: true, limit: 3 }),
]);
</script>
<template>
<AisInstantSearch :configuration="configuration" :widgets="widgets">
<AisRefinementList attribute="brand" :show-more="true" :limit="3" />
</AisInstantSearch>
</template>
If you need two independent connectors for the same attribute (for example two
<AisRefinementList> blocks whose selections must not bleed into each other), give each component a distinct id AND register a matching useAis*({...}, "id-1") / useAis*({...}, "id-2") pair.