A reusable component for Vue 3 that renders a list with a huge number of items (e.g. 1000+ items) as a grid in a performant way.

Overview

Virtual Scroll Grid for Vue 3

This is a reusable component for Vue 3 that renders a list with a huge number of items (e.g. 1000+ items) as a grid in a performant way.

Features

  • Use virtual-scrolling / windowing to render the items, so the number of DOM nodes is kept low.
  • Just use CSS grid to style your grid. Minimum styling opinions form the library.
  • Support using a paginated API to load the items in the background.
  • Support rendering placeholders for unloaded items
  • Loaded items are cached for better performance.

Code Examples

Install

npm install vue-virtual-scroll-grid

Available Props

Name Description Type Validation
length The number of items in the list number Required, an integer greater than or equal to 0
pageProvider The callback that returns a page of items as a promise (pageNumber: number, pageSize: number) => Promise Required
pageSize The number of items in a page from the item provider (e.g. a backend API) number Required, an integer greater than or equal to 1

Example:

">
<Grid :length="1000"
      :pageProvider="async (pageNumber, pageSize) => Array(pageSize).fill('x')"
      :pageSize="40"
>
  
Grid>

Available Slots

There are 3 scoped slots: default, placeholder and probe.

The default slot

The default slot is used to render a loaded item.

Props:

  • item: the loaded item that is used for rendering your item element/component.
  • index: the index of current item within the list.
  • style: the style object provided by the library that need to be set on the item element/component.

Example:

{{ item }} {{ index }}
">
<template v-slot:default="{ item, style, index }">
  <div :style="style">{{ item }} {{ index }}div>
template>

Theplaceholder slot

When an item is not loaded, the component/element in the placeholder slot will be used for rendering. The placeholder slot is optional. If missing, the space of unloaded items will be blank until they are loaded.

Props:

  • index: the index of current item within the list.
  • style: the style object provided by the library that need to be set on the item element/component.

Example:

Placeholder {{ index }}
">
<template v-slot:placeholder="{ index, style }">
  <div :style="style">Placeholder {{ index }}div>
template>

The probe slot

The probe slot is used to measure the visual size of grid item. It has no prop. You can pass the same element/component for the placeholder slot. If not provided, you must set a fixed height to grid-template-rows on your CSS grid, e.g. 200px. Otherwise, the view won't be rendered properly.

Example:

Probe
">
<template v-slot:probe>
  <div class="item">Probediv>
template>

Caveats

The library does not require items have foreknown width and height, but do require them to be styled with the same width and height under a view. E.g. the items can be 200px x 200px when the view is under 768px and 300px x 500px above 768px.

Development

Required environment variables:

  • VITE_APP_ID: An Algolia app ID
  • VITE_SEARCH_ONLY_API_KEY: The search API key for the Algolia app above
  • Setup: npm install
  • Run dev server: npm run dev
  • Lint (type check): npm run lint
  • Build the library: npm run build
  • Build the demo: npm run build -- --mode=demo
  • Preview the locally built demo: npm run serve

How to Release a New Version

npm version [major | minor | patch] -m 'build: bump version number'
npm publish
Issues
  • [BUG] tiles are still rendered as whitespace when the content length < pageSize

    [BUG] tiles are still rendered as whitespace when the content length < pageSize

    Describe the bug

    When I use eg. :pageSize="40" and I scroll all the way to the bottom, the final section of the virtual grid will render tile placeholders for content that doesn't exist.

    Since a single tile is about 1/3 of the screen height for me, it can render an immense amount of whitespace at the bottom.

    Here is the DOM what the placeholder DOM element looks like:

    image

    You see that the previous one DOM element is the last one I have with content.

    Expected behavior

    The bottom tiles should not be rendered as whitespace when not provided by pageProvider. (Eg. the page provider returns only 1 result, and pageSize is 40, then ideally we only render 1 grid row or even better, 1 grid tile.)

    bug released 
    opened by mesqueeb 17
  • Enhancement: Create 'scrollTo' method to scroll to position for a specific item (by index or key)

    Enhancement: Create 'scrollTo' method to scroll to position for a specific item (by index or key)

    Create method to scrollTo specific itembased on an index or key in a virtualized list.

    released 
    opened by Tmodurr 6
  • [BUG] Argument of type 'Ref<HTMLElement | SVGElement | VueInstance | undefined>' is not assignable to parameter of type 'MaybeElementRef'.

    [BUG] Argument of type 'Ref' is not assignable to parameter of type 'MaybeElementRef'.

    Recently I'm getting issues like these again in my typescript based project

    image

    I do have skipLibCheck: true in tsconfig, so not sure what's causing it though : S

    ERROR in ../../node_modules/vue-virtual-scroll-grid/src/Grid.vue:97:37
    TS2345: Argument of type 'Ref<HTMLElement | SVGElement | VueInstance | undefined>' is not assignable to parameter of type 'MaybeElementRef'.
      Property '[RefSymbol]' is missing in type 'Ref<HTMLElement | SVGElement | VueInstance | undefined>' but required in type 'Ref<HTMLElement | SVGElement | VueInstance | null | undefined>'.
         95 |       pageSize$: fromProp(props, "pageSize"),
         96 |       // a stream of item size measurements when it is changed
      >  97 |       itemRect$: fromResizeObserver(probeRef, "contentRect"),
            |                                     ^^^^^^^^
         98 |       // a stream of root elements when it is resized
         99 |       rootResize$: fromResizeObserver(rootRef, "target"),
        100 |       // a stream of root elements when scrolling
    
    ERROR in ../../node_modules/vue-virtual-scroll-grid/src/Grid.vue:99:39
    TS2345: Argument of type 'Ref<HTMLElement | SVGElement | VueInstance | undefined>' is not assignable to parameter of type 'MaybeElementRef'.
         97 |       itemRect$: fromResizeObserver(probeRef, "contentRect"),
         98 |       // a stream of root elements when it is resized
      >  99 |       rootResize$: fromResizeObserver(rootRef, "target"),
            |                                       ^^^^^^^
        100 |       // a stream of root elements when scrolling
        101 |       scroll$: fromWindowScroll(rootRef),
        102 |       scrollTo$: fromProp(props, "scrollTo"),
    
    ERROR in ../../node_modules/vue-virtual-scroll-grid/src/Grid.vue:101:33
    TS2345: Argument of type 'Ref<HTMLElement | SVGElement | VueInstance | undefined>' is not assignable to parameter of type 'MaybeElementRef'.
         99 |       rootResize$: fromResizeObserver(rootRef, "target"),
        100 |       // a stream of root elements when scrolling
      > 101 |       scroll$: fromWindowScroll(rootRef),
            |                                 ^^^^^^^
        102 |       scrollTo$: fromProp(props, "scrollTo"),
        103 |     });
        104 |
    
    image bug released 
    opened by mesqueeb 5
  • build(deps-dev): bump vite from 2.6.10 to 2.6.13

    build(deps-dev): bump vite from 2.6.10 to 2.6.13

    Bumps vite from 2.6.10 to 2.6.13.

    Changelog

    Sourced from vite's changelog.

    2.6.13 (2021-10-27)

    Bug Fixes

    2.6.12 (2021-10-26)

    Bug Fixes

    2.6.11 (2021-10-25)

    Bug Fixes

    Performance Improvements

    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies released 
    opened by dependabot[bot] 5
  • fix: type generation without vite-dts

    fix: type generation without vite-dts

    fixes #164

    released 
    opened by mesqueeb 4
  • [FEATURE REQUEST] improve initial load speed

    [FEATURE REQUEST] improve initial load speed

    Is your feature request related to a problem? Please describe.

    Currently for me it takes 7 seconds to load (:pageSize="40" and 3 columns)

    Describe the solution you'd like

    I'd like some advice how to improve initial load speed.

    enhancement 
    opened by mesqueeb 3
  • [BUG] TypeError: can't access property

    [BUG] TypeError: can't access property "isCE", currentRenderingInstance is null

    <template>
      <Grid :length="orderList.length" :page-provider="pageItems" :page-size="12">
        <template #probe>
          <Order :order="orderList[0]" />
        </template>
        <template #default="{ item, style, index }">
          <div :style="style">{{ item }} {{ index }}</div>
        </template>
        <template #placeholder="{ index, style }">
          <div :style="style">Placeholder {{ index }}</div>
        </template>
      </Grid>
    </template>
    
    <script lang="ts">
    import Order from "/path/to/my/component";
    import Grid from "vue-virtual-scroll-grid";
    
    return {
      components: { Order, Grid },
      mounted() {
        // getting from api
      },
      methods: {
        async pageItems(pageNumber: number, pageSize: number): Promise<unknown[]> {
          return Array(pageSize).fill("x");
        }
      }
    }
    </script>
    

    And i getting an error:

    Uncaught (in promise) TypeError: can't access property "isCE", currentRenderingInstance is null
        renderSlot runtime-core.esm-bundler.js:5799
        _sfc_render vue-virtual-scroll-grid.js:6755
        renderComponentRoot runtime-core.esm-bundler.js:424
        componentUpdateFn runtime-core.esm-bundler.js:4189
        run reactivity.esm-bundler.js:160
        setupRenderEffect runtime-core.esm-bundler.js:4315
        mountComponent runtime-core.esm-bundler.js:4098
        processComponent runtime-core.esm-bundler.js:4056
        patch runtime-core.esm-bundler.js:3651
        mountChildren runtime-core.esm-bundler.js:3847
        mountElement runtime-core.esm-bundler.js:3756
        processElement runtime-core.esm-bundler.js:3728
        patch runtime-core.esm-bundler.js:3648
        mountChildren runtime-core.esm-bundler.js:3847
        mountElement runtime-core.esm-bundler.js:3756
        processElement runtime-core.esm-bundler.js:3728
        patch runtime-core.esm-bundler.js:3648
        componentUpdateFn runtime-core.esm-bundler.js:4196
        run reactivity.esm-bundler.js:160
        setupRenderEffect runtime-core.esm-bundler.js:4315
        mountComponent runtime-core.esm-bundler.js:4098
        processComponent runtime-core.esm-bundler.js:4056
        patch runtime-core.esm-bundler.js:3651
        componentUpdateFn runtime-core.esm-bundler.js:4266
        run reactivity.esm-bundler.js:160
        callWithErrorHandling runtime-core.esm-bundler.js:6656
        flushJobs runtime-core.esm-bundler.js:6895
    

    Node: 16.9.1 Vue: 3.2.12 vue-virtual-scroll-grid: 1.2.1

    bug 
    opened by MDReal32 3
  • [FEATURE REQUEST] Support horizontal scroll

    [FEATURE REQUEST] Support horizontal scroll

    I have a use case where I need a long list of names that's horizontally scrollable. I'd love to be able to use this library as well. : )

    In my use case, the list is pre-fetched, so I would only need the render optimisations, not the "getPage" async method for retrieving more results.

    enhancement wontfix 
    opened by mesqueeb 2
  • build(deps-dev): bump @vitejs/plugin-vue from 1.6.2 to 1.7.1

    build(deps-dev): bump @vitejs/plugin-vue from 1.6.2 to 1.7.1

    Bumps @vitejs/plugin-vue from 1.6.2 to 1.7.1.

    Changelog

    Sourced from @​vitejs/plugin-vue's changelog.

    1.7.1 (2021-09-18)

    Bug Fixes

    • plugin-vue: properly handle in-template TS syntax + tests (0a2a5e1)

    1.7.0 (2021-09-18)

    Features

    • plugin-vue: support TS in template expressions (01fa2ab)
    Commits

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    dependencies released 
    opened by dependabot[bot] 2
  • fix: vue-virtual-scroll-grid build setup

    fix: vue-virtual-scroll-grid build setup

    fixes #164

    opened by mesqueeb 2
Releases(v1.3.0)
Lightweight and simple to use vue component that highlights menu items as you scroll the page, also scrolling to target section when clicked.

vue-scrollactive This component makes it simple to highlight a menu item with an 'active' class as you scroll. Highlights items with a class as you sc

Mauricio Farias Dziedzinski 510 Jan 12, 2022
Lightweight package for highlighting menu items as you scroll the page, also scrolling to target section when item clicked. Use as a vue component/directive or in vanilla js.

navscroll-js Installation This package is available on npm. Using npm: npm install --save navscroll Using yarn: yarn add navscroll Directly include it

Honoré Nintunze 56 Jan 17, 2022
Lightweight and simple to use vue component that highlights menu items as you scroll the page, also scrolling to target section when clicked.

vue-scrollactive This component makes it simple to highlight a menu item with an 'active' class as you scroll. Highlights items with a class as you sc

Mauricio Farias Dziedzinski 512 Jan 20, 2022
A managed scroller to dynamically load items

vue-managed-scroller View live demo in sandbox Installation npm install --save vue-managed-scroller or if you prefer yarn yarn add vue-managed-scroll

Justin Levine 16 Jul 21, 2021
📜 Vue.js + Stroll.js. Awesome CSS list scroll effects for Vue2.x.

vue-stroll Vue.js + Stroll.js. Awesome CSS list scroll effects for Vue2.x. See Demo Installation npm i vue-stroll -S CDN Use this URL for development

Yunwei Xiao 155 Dec 28, 2021
📜 Vue.js + Stroll.js. Awesome CSS list scroll effects for Vue2.x.

vue-stroll Vue.js + Stroll.js. Awesome CSS list scroll effects for Vue2.x. See Demo Installation npm i vue-stroll -S CDN Use this URL for development

Yunwei Xiao 155 Dec 28, 2021
Infinite scroll list for Vue.js with DOM recycling.

vue-recyclist (not maintained) Infinite scroll list for Vue.js (v2.1+) with DOM recycling. Demo Installation npm install -D vue-recyclist Import impor

Tong 261 Dec 30, 2021
infinite list based on vue2

vue-infinite-list infinite list based on vue2. Installation npm i vue-infinite-list demo npm run start Basic Use import and register the infinite li

null 27 Sep 26, 2020
A Vue component to add intersection-observer to a Vue component or HTML element.

Vue Intersect A Vue component to add intersection-observer to a Vue component or HTML element. Table of content Introduction Demo Installation Usage P

WEAREHEAVY® 312 Jan 9, 2022
A Vue.js component for detecting when components are visible in the viewport via the Vue.js scoped slots api.

vue-scrollview ScrollView is a Vue.js plugin that includes a set of components and methods for facilitating UI interactions tied to scrolling in your

Chris Hurlburt 114 Dec 30, 2021
The Simplest Scroll Area Component with custom scrollbar for Vue Js. https://bosnaufal.github.io/vue-scrollbar/

Vue Scrollbar The Simplest Scroll Area Component with custom scrollbar for Vue Js. All animation, Height and Width are pure CSS, So it's TOTALLY CUSTO

Naufal Rabbani 117 Jan 18, 2022
Vue-loadmore - A pull-down refresh and pull-up loadmore scroll component for Vue.js

vuejs-loadmore A pull-down refresh and pull-up loadmore scroll component for Vue

staticdeng 32 Jan 8, 2022
A Vue component that syncronize containers scroll positions

vue-scroll-sync A Vue component that syncronize containers scroll positions Installation npm i --save vue-scroll-sync Browser Include the script file,

null 23 Jan 11, 2022
A Back-to-top component for Vue.js, which scroll page to the top when clicked

Vue Backtotop Component A Back-to-top component for Vue.js, which scroll page to the top when clicked Demo See demo. Install via npm npm install vue-b

Caio Fernandes 182 Dec 10, 2021
A Vue.js component to top of the page

vue-scroll-up Installation Get from npm / yarn: npm i vue-scroll-up yarn add vue-scroll-up or just include vue-scroll-up.js to your view like <script

Willy Hong 7 Dec 18, 2021
👁 Declarative Vue component that emits an event when scrolled into view

vue-visibility-trigger Vue component that emits an event when scrolled into view Installation Install the package from npm by running $ yarn add vue-v

William Lindvall 5 May 30, 2021
🎰 Scroll-in text component for Vue

Scroll-in text component for Vue 'vue-scrollin' is a Vue component that scrolls through various characters on mount before revealing the correct text.

William Lindvall 60 Dec 16, 2021
A scroll to top component for Vue 3

A scroll to top component for Vue 3

Willy Hong 4 Aug 26, 2021
Vue component that provides content scrolling and zooming using mouse events or two fingers pinch on a mobile devices

vue-pinch-scroll-zoom Vue component that provides content scrolling and zooming using mouse events or two fingers pinch on a mobile devices example: h

CoddiCat 10 Dec 23, 2021