Skip to content

Infinite Scroll

Due to VitePress restriction, it's not possible to show the infinite scroll demo here.

Please refer to the demo component source-code.

vue
<script setup lang="ts">
import type { Option } from "../../src";
import { ref } from "vue";
import VueSelect from "../../src";

// Track the selected value
const selected = ref<string | null>(null);

// Track loading state when fetching more options
const isLoading = ref(false);

// Track current page for pagination
const currentPage = ref(1);

// Store all available options
const options = ref<Option<string>[]>([]);

// Simulate an API call to fetch more books
const fetchMoreBooks = async (page: number) => {
  isLoading.value = true;

  // Simulate API delay
  await new Promise((resolve) => setTimeout(resolve, 500));

  // Generate 10 new books for each page
  const newBooks = Array.from({ length: 10 }, (_, i) => {
    const bookNumber = (page - 1) * 10 + i + 1;
    return {
      label: `Book #${bookNumber}`,
      value: `book_${bookNumber}`,
    };
  });

  options.value = [...options.value, ...newBooks];
  currentPage.value = page;
  isLoading.value = false;
};

// Handle scroll event in the menu container
const handleScroll = (e: Event) => {
  const target = e.target as HTMLElement;
  const isAtBottom = target.scrollHeight - target.scrollTop === target.clientHeight;

  if (isAtBottom && !isLoading.value) {
    fetchMoreBooks(currentPage.value + 1);
  }
};

// Load initial data
fetchMoreBooks(1);
</script>

<template>
  <VueSelect
    v-model="selected"
    :options="options"
    :is-multi="false"
    placeholder="Pick a book"
    :classes="{ menuContainer: 'custom-menu-container' }"
  >
    <template #menu-container="{ defaultContent }">
      <div
        class="infinite-scroll-container"
        @scroll="handleScroll"
      >
        <component :is="defaultContent" />

        <div v-if="isLoading" class="loading-indicator">
          Loading more books...
        </div>
      </div>
    </template>
  </VueSelect>

  <p class="selected-value">
    Selected book value: {{ selected || "none" }}
  </p>
</template>

<style scoped>
:deep(.custom-menu-container) {
  max-height: 202px;
}

.infinite-scroll-container {
  max-height: 200px;
  overflow-y: auto;
}

.loading-indicator {
  text-align: center;
  padding: 8px;
  font-size: 14px;
  color: #666;
}
</style>