Nuxt Swiftsearch
Examples

Pagination Route Sync

Keep pagination state in URLs and restore it on direct loads.

The playground shows two variants:

  • query-string sync through useAisRouter(),
  • custom path sync (/pagination/page/:page) with custom router/state mapping.
components/PaginatedSearch.vue
<template>
  <AisInstantSearch :configuration="configuration">
    <AisConfigure :search-parameters="{ hitsPerPage: 20 }" />
    <AisHits />
    <AisPagination :padding="2" />
  </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 configuration = {
  indexName: "instant_search",
  searchClient: client,
  routing: {
    router: algoliaRouter.value.router,
    stateMapping: singleIndexMapping("instant_search"),
  },
};
</script>

Variant B: path-based page sync (advanced)

If you want clean paths like /pagination/page/3, use a custom router adapter and mapping (the same idea used in the playground).

composables/useCustomRouting.ts
export const useCustomRouting = () => {
  const router = useRouter();

  return ref({
    router: {
      read() {
        const query = router.currentRoute.value.query;
        const isPagedRoute = router.currentRoute.value.name === "pagination-page-page";
        return isPagedRoute
          ? { ...query, page: Number(router.currentRoute.value.params.page) }
          : query;
      },
      write(routeState) {
        if (routeState?.page) {
          router.push({
            name: "pagination-page-page",
            params: { page: String(routeState.page) },
            query: { ...routeState, page: undefined },
          });
          return;
        }

        router.push({ query: { ...routeState } });
      },
      createURL(routeState) {
        return router.resolve({ query: routeState }).href;
      },
      onUpdate(cb) {
        if (typeof window === "undefined") return;
        this._removeAfterEach = router.afterEach(() => cb(this.read()));
      },
      dispose() {
        this._removeAfterEach?.();
      },
    },
  });
};

Use Variant B only when route shape is a product requirement; otherwise Variant A is simpler and robust.

Copyright © 2026