Nuxt Swiftsearch
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>
Copyright © 2026