Infinite scroll
Vue Bootstrap 5 Infinite scroll
This feature adds a scroll event listener (to the window or the component it's attached to if it has the overflow-y property set to scroll) and calls a callback method every time a user reaches an end of a page/container.
Note: Read the API tab to find all available options and advanced customization
Basic example
Scroll down the container below to add more items.
Note: Your element should be scrollable, for
example, it should have overflow-y: scroll
property
like in the example below.
- Angry
- Dizzy
- Flushed
- Frown
- Grimace
- Grin
<template>
<MDBListGroup
class="container"
style="max-height: 261px; overflow-y: scroll"
v-mdb-infinite-scroll="infiniteScroll1"
>
<MDBListGroupItem
v-for="(item, i) in listGroup1"
:key="i"
class="d-flex align-items-center"
>
<MDBIcon
iconStyle="far"
:icon="item.icon"
size="3x"
class="me-4"
/>
{{ item.content }}
</MDBListGroupItem>
</MDBListGroup>
</template>
<script>
import { mdbInfiniteScroll, MDBIcon, MDBListGroup, MDBListGroupItem } from 'mdb-vue-ui-kit';
import { ref } from "vue";
export default {
directives: {
mdbInfiniteScroll
},
components: {
MDBIcon,
MDBListGroup,
MDBListGroupItem
},
setup() {
const icons = [
"Sad-Tear",
"Meh-Blank",
"Smile-Wink",
"Tired",
"Surprise",
"Kiss-Beam",
"Laugh-Squint"
];
const listGroup1 = ref([
{
icon: "angry",
content: "Angry"
},
{
icon: "dizzy",
content: "Dizzy"
},
{
icon: "flushed",
content: "Flushed"
},
{
icon: "frown",
content: "Frown"
},
{
icon: "grimace",
content: "Grimace"
},
{
icon: "grin",
content: "Grin"
}
]);
const itemIndex1 = ref(0);
const infiniteScroll1 = () => {
if (itemIndex1.value === icons.length - 1) {
return;
}
listGroup1.value.push({
icon: icons[itemIndex1.value].toLowerCase(),
content: icons[itemIndex1.value]
});
itemIndex1.value++;
};
return {
listGroup1,
infiniteScroll1
}
}
};
</script>
Direction
Use v-mdb-infinite-scroll:x
to change the scrolling
direction to horizontall.
<template>
<div
class="text-center py-3"
style="max-width: 1500px; overflow-x: scroll; white-space: nowrap"
v-mdb-infinite-scroll:x="infiniteScroll2"
>
<span v-for="(item, i) in listGroup2" :key="i" class="mx-5">
<MDBIcon
iconStyle="far"
:icon="item.icon"
size="3x"
class="me-4"
/>
{{ item.content }}
</span>
</div>
</template>
<script>
import { mdbInfiniteScroll, MDBIcon } from 'mdb-vue-ui-kit';
import { ref } from "vue";
export default {
directives: {
mdbInfiniteScroll
},
components: {
MDBIcon
},
setup() {
const icons = [
"Sad-Tear",
"Meh-Blank",
"Smile-Wink",
"Tired",
"Surprise",
"Kiss-Beam",
"Laugh-Squint"
];
const listGroup2 = ref([
{
icon: "angry",
content: "Angry"
},
{
icon: "dizzy",
content: "Dizzy"
},
{
icon: "flushed",
content: "Flushed"
},
{
icon: "frown",
content: "Frown"
},
{
icon: "grimace",
content: "Grimace"
},
{
icon: "grin",
content: "Grin"
}
]);
const itemIndex2 = ref(0);
const infiniteScroll2 = () => {
if (itemIndex2.value === icons.length - 1) {
return;
}
listGroup2.value.push({
icon: icons[itemIndex2.value].toLowerCase(),
content: icons[itemIndex2.value]
});
itemIndex2.value++;
};
return {
listGroup2,
infiniteScroll2
}
}
};
</script>
Spinners and asynchronous data
<template>
<div
class="infinite-scroll py-3 text-center"
v-mdb-infinite-scroll="loadImages"
style="max-height: 500px; overflow-y: scroll"
>
<div id="images">
<img
v-for="(image, i) in images"
:key="i"
:src="image"
class="img-fluid mb-3"
/>
</div>
<MDBSpinner v-if="isLoading" class="mx-auto" />
</div>
</template>
<script>
import { mdbInfiniteScroll, MDBSpinner } from 'mdb-vue-ui-kit';
import { ref } from "vue";
export default {
directives: {
mdbInfiniteScroll
},
components: {
MDBSpinner
},
setup() {
const images = ref([
"https://mdbootstrap.com/img/Photos/Slides/img%20(100).webp",
"https://mdbootstrap.com/img/Photos/Slides/img%20(105).webp",
"https://mdbootstrap.com/img/Photos/Slides/img%20(106).webp"
]);
const isLoading = ref(false);
const loadImages = () => {
// Make spinner visible
isLoading.value = true;
// Fetch your API
fetch('YOUR_API/getNextItem')
.then(response => response.json)
.then(imgUrl => {
// Hide spinner after data loads
isLoading.value = false;
// Append an image element
images.value.push(imgUrl);
})
}
return {
images,
isLoading,
loadImages
}
}
};
</script>
Window
You can apply the mdbInfiniteScroll
directive to a
window by placing
v-mdb-infinite-scroll:window
directive to the container
of your scrolling elements.
<template>
<main class="my-4" v-mdb-infinite-scroll:window="loadImages">
<MDBContainer>
<section class="text-center mb-4" id="posts">
<MDBRow v-for="(pair, i) in imagePairs" :key="i">
<MDBCol md="6" class="mb-4" v-for="(image, i) in pair" :key="i">
<div
class="bg-image hover-overlay ripple shadow-1-strong rounded mb-4"
v-mdb-ripple="{ color: 'light' }"
>
<img
v-mdb-lazy="{
src: image.src,
placeholder: 'https://place-hold.it/1321x583?text=Loading'
}"
class="w-100"
/>
<a href="#!">
<div
class="mask"
style="background-color: rgba(251, 251, 251, 0.2);"
></div>
</a>
</div>
<h5>{{ image.title }}</h5>
<p>
{{ image.text }}
</p>
<MDBBtn tag="a" color="info" rounded href="#!">Read more</MDBBtn>
</MDBCol>
</MDBRow>
<MDBRow v-if="isLoading">
<MDBCol md="12">
<MDBSpinner class="mx-auto"></MDBSpinner>
</MDBCol>
</MDBRow>
</section>
</MDBContainer>
</main>
</template>
<script>
import {
mdbInfiniteScroll,
mdbLazy,
mdbRipple,
MDBContainer,
MDBRow,
MDBCol,
MDBBtn,
MDBSpinner
} from "mdb-vue-ui-kit";
import { ref, nextTick } from "vue";
export default {
name: "infinite-scroll-window",
components: { MDBContainer, MDBRow, MDBCol, MDBBtn, MDBSpinner },
directives: {
mdbInfiniteScroll,
mdbLazy,
mdbRipple
},
setup() {
const items = [
[
{
src: "https://mdbcdn.b-cdn.net/img/Photos/Others/images/31.webp",
title: "This is an title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
},
{
src: "https://mdbcdn.b-cdn.net/img/Photos/Others/images/23.webp",
title: "This is an title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
}
],
[
{
src: "https://mdbcdn.b-cdn.net/img/Photos/Others/images/29.webp",
title: "This is an title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
},
{
src: "https://mdbcdn.b-cdn.net/img/Photos/Others/images/27.webp",
title: "This is an title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
}
],
[
{
src: "https://mdbcdn.b-cdn.net/img/Photos/Others/images/25.webp",
title: "This is an title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
},
{
src: "https://mdbcdn.b-cdn.net/img/Photos/Others/images/24.webp",
title: "This is an title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
}
],
[
{
src: "https://mdbcdn.b-cdn.net/img/Photos/Others/images/31.webp",
title: "This is an title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
},
{
src: "https://mdbcdn.b-cdn.net/img/Photos/Others/images/32.webp",
title: "This is an title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
}
]
];
const imagePairs = ref([
[
{
src: "https://mdbootstrap.com/img/Photos/Others/images/29.webp",
title: "This is a title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
},
{
src: "https://mdbootstrap.com/img/Photos/Others/images/27.webp",
title: "This is a title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
}
],
[
{
src: "https://mdbootstrap.com/img/Photos/Others/images/25.webp",
title: "This is a title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
},
{
src: "https://mdbootstrap.com/img/Photos/Others/images/24.webp",
title: "This is a title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
}
],
[
{
src: "https://mdbootstrap.com/img/Photos/Others/images/31.webp",
title: "This is a title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
},
{
src: "https://mdbootstrap.com/img/Photos/Others/images/23.webp",
title: "This is a title of the article",
text:
"Lorem ipsum dolor sit amet consectetur adipisicing elit. Quisquam cupiditate veniam voluptatibus laudantium cum dolorem illo. Quos architecto deserunt saepe."
}
]
]);
const itemsIndex = ref(0);
const isLoading = ref(false);
const loadImages = () => {
if (itemsIndex.value === items.length - 1) {
return;
}
isLoading.value = true;
imagePairs.value.push(items[itemsIndex.value]);
nextTick(() => {
isLoading.value = false;
});
itemsIndex.value++;
};
return {
imagePairs,
isLoading,
loadImages
};
}
};
</script>
Infinite scroll - API
Import
<script>
import {
mdbInfiniteScroll
} from 'mdb-vue-ui-kit';
</script>
Arguments
Argument | Description |
---|---|
x
|
Set horizontal scroll direction |
window
|
Set scroll parent on window element |