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>
          
        
    
        
            
            <script setup lang="ts">
              import {
                mdbInfiniteScroll as vMdbInfiniteScroll,
                MDBIcon,
                MDBListGroup,
                MDBListGroupItem
              } from 'mdb-vue-ui-kit';
              import { ref } from "vue";

              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++;
              };
            </script>
          
        
    

Direction

Use v-mdb-infinite-scroll:x to change the scrolling direction to horizontall.

Angry Dizzy Flushed Grimace Grin
        
            
            <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>
          
        
    
        
            
            <script setup lang="ts">
              import { mdbInfiniteScroll as vMdbInfiniteScroll, MDBIcon } from 'mdb-vue-ui-kit';
              import { ref } from "vue";

              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++;
              };
            </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>
          
        
    
        
            
            <script setup lang="ts">
              import { mdbInfiniteScroll as vMdbInfiniteScroll, MDBSpinner } from 'mdb-vue-ui-kit';
              import { ref } from "vue";

              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);
                  })
              };
            </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>
          
        
    
        
            
            <script setup lang="ts">
              import {
                mdbInfiniteScroll as vMdbInfiniteScroll,
                mdbLazy as vMdbLazy,
                mdbRipple as vMdbRipple,
                MDBContainer,
                MDBRow,
                MDBCol,
                MDBBtn,
                MDBSpinner
              } from "mdb-vue-ui-kit";
              import { ref, nextTick } from "vue";

              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++;
              };
            </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