InfiniteScroll
Automatically load more data when scrolling to the bottom. Uses IntersectionObserver for efficient scroll detection.
Preview
Installation
pnpm dlx brutx-vue@latest add infinite-scrollUsage
<script setup>
import { ref } from 'vue'
import { InfiniteScroll } from 'brutx-ui-vue'
const items = ref(Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`))
const loading = ref(false)
async function loadMore() {
loading.value = true
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1000))
const newItems = Array.from(
{ length: 10 },
(_, i) => `Item ${items.value.length + i + 1}`
)
items.value.push(...newItems)
loading.value = false
}
</script>
<template>
<InfiniteScroll @load="loadMore">
<div v-for="item in items" :key="item" class="p-4 border-b">
{{ item }}
</div>
</InfiniteScroll>
</template>With Custom Loading
<script setup>
import { ref } from 'vue'
import { InfiniteScroll, Spinner } from 'brutx-ui-vue'
const items = ref([])
async function loadMore() {
// Load data
}
</script>
<template>
<InfiniteScroll @load="loadMore">
<div v-for="item in items" :key="item.id">
{{ item.name }}
</div>
<template #loading>
<div class="flex items-center justify-center py-4">
<Spinner size="sm" />
<span class="ml-2">Loading more...</span>
</div>
</template>
</InfiniteScroll>
</template>Disabled State
<script setup>
import { ref } from 'vue'
import { InfiniteScroll } from 'brutx-ui-vue'
const items = ref([])
const hasMore = ref(true)
async function loadMore() {
if (!hasMore.value) return
// Load data...
// If no more data:
// hasMore.value = false
}
</script>
<template>
<InfiniteScroll :disabled="!hasMore" @load="loadMore">
<div v-for="item in items" :key="item.id">
{{ item.name }}
</div>
</InfiniteScroll>
</template>API Reference
| Name | Type | Default | Description |
|---|---|---|---|
distance | number | undefined | 100 | The number of pixels by which the intersection observer trigger area expands beyond the viewport. |
DetailsDeclared typenumber | undefined Default value details
Sourcepackages/ui/src/components/infinite-scroll/InfiniteScroll.vue | |||
delay | number | undefined | 200 | The debounce delay in milliseconds after the loading sentinel enters the trigger area. |
DetailsDeclared typenumber | undefined Default value details
Sourcepackages/ui/src/components/infinite-scroll/InfiniteScroll.vue | |||
disabled | boolean | undefined | false | Disables load detection and disconnects the observer; loading is not triggered while disabled. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/infinite-scroll/InfiniteScroll.vue | |||
immediate | boolean | undefined | true | Requests a load on mount and after re-enabling when true; when false, loading is triggered only by the sentinel entering the expanded viewport. |
DetailsDeclared typeboolean | undefined Literal values
Default value details
Sourcepackages/ui/src/components/infinite-scroll/InfiniteScroll.vue | |||
class | string | undefined | undefined | CSS classes added to the outer container for the list, loading state, and observer sentinel. |
DetailsDeclared typestring | undefined Default value details
Sourcepackages/ui/src/components/infinite-scroll/InfiniteScroll.vue | |||
| Name | Signature or type | Description |
|---|---|---|
@load | [] | Emitted without a payload when more data should load after the debounce delay. Call resetLoading() after the parent finishes loading. |
DetailsDeclared type[] Sourcepackages/ui/src/components/infinite-scroll/InfiniteScroll.vue | ||
| Name | Signature or type | Description |
|---|---|---|
#default | {} | The list or scrolling content to extend as more data is loaded. |
DetailsDeclared type{}Sourcepackages/ui/src/components/infinite-scroll/InfiniteScroll.vue | ||
#loading | {} | A custom indicator shown while a load is in progress; pulsing dots are shown when omitted. |
DetailsDeclared type{}Sourcepackages/ui/src/components/infinite-scroll/InfiniteScroll.vue | ||
| Name | Signature or type | Description |
|---|---|---|
resetLoading | () => void | Marks loading as complete and checks the sentinel again. If it remains inside the expanded viewport, another load may fire immediately; set disabled to true when no more data is available. |
DetailsDeclared type() => void Sourcepackages/ui/src/components/infinite-scroll/InfiniteScroll.vue | ||
Composable
For more flexible usage, use the useInfiniteScroll composable:
<script setup>
import { ref } from 'vue'
import { useInfiniteScroll } from 'brutx-ui-vue'
const containerRef = ref(null)
const items = ref([])
const { isLoading, resetLoading } = useInfiniteScroll(containerRef, {
distance: 100,
delay: 200,
onLoad: async () => {
// Load data
const newItems = await fetchItems()
items.value.push(...newItems)
resetLoading()
},
})
</script>
<template>
<div ref="containerRef">
<div v-for="item in items" :key="item.id">
{{ item.name }}
</div>
</div>
</template>useInfiniteScroll Options
| Option | Type | Default | Description |
|---|---|---|---|
distance | number | 100 | Trigger distance threshold in pixels |
delay | number | 200 | Debounce delay in milliseconds |
disabled | boolean | false | Whether disabled |
immediate | boolean | true | Whether to check immediately on mount |
onLoad | () => void | — (required) | Load callback |
useInfiniteScroll Returns
| Property | Type | Description |
|---|---|---|
isLoading | Ref<boolean> | Whether currently loading |
resetLoading | () => void | Reset loading state |
Accessibility
- Screen Readers: Loading state is announced
- Reduced Motion: Loading animation respects
prefers-reduced-motion