> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Infinite scroll with Vue InstantSearch

> Implement an infinite scroll experience with Vue InstantSearch.

export const Index = () => <Tooltip tip="An Algolia index is a searchable dataset that consists of records and configuration settings. These settings define how the records are searched and ranked.">
    index
  </Tooltip>;

An "infinite list" is a common way of displaying results. It's especially well-suited to mobile devices and has two variants:

* **Infinite hits** with a "See more" button at the end of a batch of results. Implement this with InstantSearch's [`ais-infinite-hits`](/doc/api-reference/widgets/infinite-hits/vue) widget.
* **Infinite scroll** uses a listener on the scroll event (called when users have scrolled to the end of the first batch of results). The following guidance implements such an infinite scroll. Find the complete example on [GitHub](https://github.com/algolia/doc-code-samples/tree/master/vue-instantsearch/infinite-scroll).

<Note>
  This code has been specifically created for Vue 2. Some [modifications](https://v3-migration.vuejs.org/) may be required for it to work correctly in Vue 3.
</Note>

## No hits

If there are no hits, you should [display a message to users and clear filters](/doc/guides/building-search-ui/going-further/conditional-display/vue#handling-no-results) so they can start over.

## Display a list of hits

Render the results with the [`ais-infinite-hits`](/doc/api-reference/widgets/infinite-hits/vue#customize-the-ui)  connector.
There's an external `Hit` component but it's not the point of this guide.
The intent is to keep the code simple.

<Note>
  Read more about connectors in the [customizing widgets guide](/doc/guides/building-search-ui/widgets/customize-an-existing-widget/vue).
</Note>

<CodeGroup>
  ```html Vue 3 theme={"system"}
  <template>
    <ol v-if="state">
      <li v-for="hit in state.hits" :key="hit.objectID">
        <slot name="item" :item="hit"> </slot>
      </li>
    </ol>
  </template>

  <script>
  import { createWidgetMixin } from 'vue-instantsearch/vue3/es';
  import { connectInfiniteHits } from 'instantsearch.js/es/connectors';

  export default {
    mixins: [createWidgetMixin({ connector: connectInfiniteHits })],
  };
  </script>
  ```

  ```html Vue 2 theme={"system"}
  <template>
    <ol v-if="state">
      <li v-for="hit in state.items" :key="hit.objectID">
        <slot name="item" :item="hit"> </slot>
      </li>
    </ol>
  </template>

  <script>
  import { createWidgetMixin } from 'vue-instantsearch';
  import { connectInfiniteHits } from 'instantsearch.js/es/connectors';

  export default {
    mixins: [createWidgetMixin({ connector: connectInfiniteHits })],
  };
  </script>
  ```
</CodeGroup>

## Track the scroll position

Once you have your results, the next step is to track the scroll position to determine when the rest of the content needs to be loaded (using the Intersection Observer API). Use the API to track when the bottom of the list (the "sentinel" element) enters the viewport. You can reuse the same element across different renders. The [Web Fundamentals](https://web.dev/articles/intersectionobserver/) website discusses the use of this API in more detail.

You can use the [vue-observe-visibility](https://github.com/Akryum/vue-observe-visibility) library to determine when the "sentinel" is visible.

<CodeGroup>
  ```html Vue 3 theme={"system"}
  <template>
    <ol v-if="state">
      <li v-for="hit in state.items" :key="hit.objectID">
        <slot name="item" :item="hit"> </slot>
      </li>
      <li class="sentinel" v-observe-visibility="visibilityChanged" />
    </ol>
  </template>

  <script>
  import { createWidgetMixin } from 'vue-instantsearch/vue3/es';
  import { connectInfiniteHits } from 'instantsearch.js/es/connectors';

  export default {
    mixins: [createWidgetMixin({ connector: connectInfiniteHits })],
    methods: {
      visibilityChanged(isVisible, e) {
        console.log(isVisible, e);
      },
    },
  };
  </script>

  <style scoped>
  .sentinel {
    list-style-type: none;
  }
  </style>
  ```

  ```html Vue 2 theme={"system"}
  <template>
    <ol v-if="state">
      <li v-for="hit in state.items" :key="hit.objectID">
        <slot name="item" :item="hit"> </slot>
      </li>
      <li class="sentinel" v-observe-visibility="visibilityChanged" />
    </ol>
  </template>

  <script>
  import { createWidgetMixin } from 'vue-instantsearch';
  import { connectInfiniteHits } from 'instantsearch.js/es/connectors';

  export default {
    mixins: [createWidgetMixin({ connector: connectInfiniteHits })],
    methods: {
      visibilityChanged(isVisible, e) {
        console.log(isVisible, e);
      },
    },
  };
  </script>

  <style scoped>
  .sentinel {
    list-style-type: none;
  }
  </style>
  ```
</CodeGroup>

<Note>
  This implementation uses the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API). To support [Internet Explorer 11](https://wikipedia.org/wiki/Internet_Explorer_11) you need a [polyfill](https://wikipedia.org/wiki/Polyfill_\(programming\)) for
  `IntersectionObserver`. A browser API is used in the example, but you can apply the concepts to any infinite scroll library.
</Note>

## Retrieve more results

Now that you can track when you reach the end of the results, use the [showMore](/doc/api-reference/widgets/infinite-hits/js#param-show-more) function inside the callback function `onSentinelIntersection`.
**Only trigger the function when there are still results to retrieve.**
For this use case, the connector provides a prop [isLastPage](/doc/api-reference/widgets/infinite-hits/js#param-is-last-page) that indicates if you still have results to load.

```html Vue icon=code-xml theme={"system"}
<script>
export default {
  methods: {
    visibilityChanged(isVisible) {
      if (isVisible && !this.state.isLastPage) {
        this.state.showMore();
      }
    },
  },
};
</script>
```

## Show more than 1,000 hits

To ensure excellent performance, the default limit for the number of hits you can retrieve for a query is
1,000.

<CodeGroup>
  ```cs C# theme={"system"}
  var response = await client.SetSettingsAsync(
    "INDEX_NAME",
    new IndexSettings { PaginationLimitedTo = 1000 }
  );
  ```

  ```dart Dart theme={"system"}
  final response = await client.setSettings(
    indexName: "INDEX_NAME",
    indexSettings: IndexSettings(
      paginationLimitedTo: 1000,
    ),
  );
  ```

  ```go Go theme={"system"}
  response, err := client.SetSettings(client.NewApiSetSettingsRequest(
    "INDEX_NAME",
    search.NewEmptyIndexSettings().SetPaginationLimitedTo(1000)))
  if err != nil {
    // handle the eventual error
    panic(err)
  }
  ```

  ```java Java theme={"system"}
  UpdatedAtResponse response = client.setSettings("INDEX_NAME", new IndexSettings().setPaginationLimitedTo(1000));
  ```

  ```js JavaScript theme={"system"}
  const response = await client.setSettings({
    indexName: 'theIndexName',
    indexSettings: { paginationLimitedTo: 1000 },
  });
  ```

  ```kotlin Kotlin theme={"system"}
  var response =
    client.setSettings(
      indexName = "INDEX_NAME",
      indexSettings = IndexSettings(paginationLimitedTo = 1000),
    )
  ```

  ```php PHP theme={"system"}
  $response = $client->setSettings(
      'INDEX_NAME',
      ['paginationLimitedTo' => 1000,
      ],
  );
  ```

  ```python Python theme={"system"}
  response = client.set_settings(
      index_name="INDEX_NAME",
      index_settings={
          "paginationLimitedTo": 1000,
      },
  )
  ```

  ```ruby Ruby theme={"system"}
  response = client.set_settings("INDEX_NAME", Algolia::Search::IndexSettings.new(pagination_limited_to: 1000))
  ```

  ```scala Scala theme={"system"}
  val response = Await.result(
    client.setSettings(
      indexName = "INDEX_NAME",
      indexSettings = IndexSettings(
        paginationLimitedTo = Some(1000)
      )
    ),
    Duration(100, "sec")
  )
  ```

  ```swift Swift theme={"system"}
  let response = try await client.setSettings(
      indexName: "INDEX_NAME",
      indexSettings: IndexSettings(paginationLimitedTo: 1000)
  )
  ```
</CodeGroup>

If you need to show more than 1,000 hits, you can set a different limit using the [`paginationLimitedTo`](/doc/api-reference/api-parameters/paginationLimitedTo) parameter.
The higher you set this limit, the slower your search performance can become.

<Note>
  Increasing the limit doesn't mean you can go until the end of the hits,
  but just that Algolia will go as far as possible in the <Index /> to retrieve results in a reasonable time.
</Note>
