Examples
Typed transformItems with Generics
Type-safe slot payloads when transformItems enriches widget items.
Use this pattern when transformItems adds derived fields and you want those fields typed in slot props.
Hits example
pages/search.vue
<template>
<AisInstantSearch :configuration="configuration">
<AisSearchBox placeholder="Search products" />
<!-- @vue-generic {ProductHit} -->
<AisHits :transform-items="transformHits">
<template #item="{ item }">
<article>
<h3>{{ item.name }}</h3>
<p>{{ item.brandLabel }} - {{ item.priceLabel }}</p>
</article>
</template>
</AisHits>
</AisInstantSearch>
</template>
<script setup lang="ts">
import { algoliasearch } from "algoliasearch";
import type { BaseHit, Hit } from "instantsearch.js/es/types";
type ProductHit = BaseHit & {
name: string;
brandLabel: string;
priceLabel: string;
};
const configuration = {
indexName: "instant_search",
searchClient: algoliasearch("latency", "6be0576ff61c053d5f9a3225e2a90f76"),
};
const transformHits = (items: Array<Hit<BaseHit>>): Array<Hit<ProductHit>> => {
return items.map((item) => ({
...item,
brandLabel: String(item.brand ?? "Unknown brand"),
priceLabel: typeof item.price === "number" ? `$${item.price.toFixed(2)}` : "Price unavailable",
}));
};
</script>
Refinement list example
<script setup lang="ts">
import type { RefinementListItem } from "instantsearch.js/es/connectors/refinement-list/connectRefinementList";
type BrandFacet = RefinementListItem & {
visualLabel: string;
};
const transformBrands = (items: RefinementListItem[]): BrandFacet[] => {
return items.map((item) => ({
...item,
visualLabel: `${item.label} (${item.count})`,
}));
};
</script>
<template>
<!-- @vue-generic {BrandFacet} -->
<AisRefinementList attribute="brand" :transform-items="transformBrands">
<template #item="{ item }">
{{ item.visualLabel }}
</template>
</AisRefinementList>
</template>