Virtual Scrolling Grid made for VueJS based on CSS grids.


Vue Virtual Grid

Virtual Scrolling Grid made for VueJS based on CSS grids.

NPM Package | Demo Website

  • Render any Vue Component (images, iframes, content) of a known width/height inside.
  • Variable height items in the same row and variable width items (based on columns).
  • Highly customizable (custom loader, rendering, debug...).
  • Rendering is done with virtual scrolling (aka windowing).
  • Supports infinite scroll!


npm install --save vue-virtual-grid


Import VirtualGrid from the package:

import VirtualGrid from 'vue-virtual-grid';

Register it as on of your components:

components: {

In your template you can add:

<VirtualGrid :items="yourDataSet" :updateFunction="yourGetDataFunction" />

The items property is requeried and should be an array of the following object:

    id: string, // binding id (must be unique)
    injected?: string, // custom param, pass an object with what you want inside (optional)
    height: number, // original height of the item
    width?: number, // original width of the item (optional: if not set, height will not be adjusted by getItemRatioHeight)
    columnSpan: number, // how many columns will use your item (put 0 if you want the full width)
    newRow?: boolean, // if the item should appear on the next row (optional)
    renderComponent: Component // A VueJS component (custom template of your choice) to render the item (passed as prop `item`)

You can update the items property at any time (and thus decide what can of storage you want to use) and the grid layout will be recomputed.

Customizing the Grid

The VirtualGrid also takes multiple custom optional functions/variables as properties

  • updateFunction: An async function that will populate the grid, constructor is the following updateFunction() => Promise . For synchronous function just return immediately with Promise.resolve(boolean) for instance.
  • getGridGap: A function that will define the gap between elements of the grid, constructor is the following getGridGap(elementWidth: number, windowHeight: number) => number.
  • getColumnCount: A function that set the width of columns in the grid, constructor is the following getColumnCount(elementWidth: number) => number;.
  • getWindowMargin: A function that set the margin size used for windowing (virtualization), constructor is the following getWindowMargin(windowHeight: number) => number;.
  • getItemRatioHeight: A function that provides a way to adjust the item height by computing the initial height/width ratio and the column width (by default it preserves ratio), constructor is the following getItemRatioHeight(height: number, width: number, columnWidth: number) => number;.
  • updateTriggerMargin: A number of pixels to the bottom of the page that will trigger the updateFunction.
  • loader: A VueJS Component to display a loader when waiting for the next batch of data.
  • debug: A boolean to activate debug log and monitor when batches are trigger and bottom reached for instance.

Properties are provided with default functions that you can use or get inspired from in src/utils.ts.

The function updateFunction should update the list of items that will be rendered (each item should look like the Item object presented before) and return (with a Promise) a boolean that signify that the last batch was loaded (bottom reached) or not.

The property injected does not impact the computation, it is here to pass custom data to the final component.

With default getItemRatioHeight, in the returned object to your renderComponent the height property will be recomputed depending on the column size and the width will be set to the column width multiplied by the column span of the item. Note that it will always keep the original ratio.

Important note: the component that will render the item should respect the returned height otherwise there will be a difference between computation and rendering (in other words, you will see glitches).

Last but not least, the resetGrid() method is exposed to parent in case you want to clear the grid :)

Passing events to the grid

The grid will pass any events attached to it to its children.

<VirtualGrid @custom-event="someMethod" />

That way, in your children Component, you can emit to this event and use the parent method.

this.$emit('custom-event', someArguments);

On the demo you can try this by clicking on a section title, it will display an alert box from the parent component.

Typescript support

If you're using Typescript you can import typing for Item and provide custom typing for injected data:

import { Item } from 'vue-virtual-grid';

interface Image {
    alt: string;
    url: string;

const item: Item<Image>;

You can also import the typing for utils methods with VirtualGridInterface.

Live example

If you want a live example, you can take a look at the demo (link at the top) and check the corresponding code in example/.


Anyone is welcome to contribute (this project is not perfect obviously).

Install current dependencies

npm ci

Build and try the example

npm run serve:example

Compiles lib for production

npm run build

Lints and fixes files

npm run lint


This is based on React work here:

Kudos to Jamie!


Corentin Mors
  • Having trouble using the component

    Having trouble using the component

    I have the component declared by doing the following:

            <v-layout class="display">
              <VirtualGrid :items="mediaItems"

    the display class is defined as:

    .album-display {
      overflow: scroll;
      width: 100%;
      height: 100%;
      align-items: stretch;
      align-content: stretch;
      background-color: blue;

    mediaItems is a computed property and looks like:

          let mediaItems = ( item, index ) =>
            return {
              id: `${index}`,
              height: 400,
              width: 400,
              columnSpan: 1,
              renderComponent: MediaItem
          return mediaItems;

    this.items is defined to be:

    items: [ "[0] - onodit", "[1] - Is", "[2] - whilel", "[3] - Coxise", "[4] - Prods", "[5] - mandmi", "[6] - eciand", "[7] - FIRS", "[8] - ho", "[9] - chabli", "[10] - 1.7%", "[11] - atic", "[12] - oroder", "[13] - he", "[14] - aremy", "[15] - Lost,", "[16] - are", "[17] - sion", "[18] - and", "[19] - Centor", "[20] - hamate", "[21] - e.", "[22] - of", "[23] - abok", "[24] - an", "[25] - used", "[26] - fortio", "[27] - wity", "[28] - Theent", "[29] - inal", "[30] - blonti", "[31] - ionad", "[32] - aned", "[33] - Prics", "[34] - In", "[35] - inal", "[36] - mend", "[37] - moract", "[38] - re", "[39] - ing", "[40] - ge", "[41] - a", "[42] - par", "[43] - frobe", "[44] - hough", "[45] - com", "[46] - eummun", "[47] - ats", "[48] - deritu", "[49] - mic", "[50] - he", "[51] - the", "[52] - dom", "[53] - to", "[54] - comess", "[55] - in", "[56] - (2)", "[57] - the", "[58] - ch", "[59] - this" ],

    The MediaItem Component looks like:

      <div class="item">
        {{ item }}
    export default
      name: "MediaItem",
        item: {
          required: true
    <style scoped>
    .item {
      width: 400px;
      height: 400px;
      background-color: yellowgreen;
      overflow: hidden;

    There are two problems:

    1. It only renders the first eight items
    2. It is not filling the space well...I would expect multiple columns

    i am sure I am missing something easy, but I am not sure what that is yet.

    It looks like:

    From Clipboard

    opened by James-Hudson3010 2
  • Q: Does it destroy elements not (anymore) in the visible Window?

    Q: Does it destroy elements not (anymore) in the visible Window?

    Given you have a very large list of elements (10 of thousands), will it destroy those elements that are no longer visible anymore because the user has scrolled over them already? Otherwise I suppose performance will go down, if there are too many objects in the DOM.

    Hope the question is clear & Thanks

    opened by hulk66 1
  • reason to not use IntersectionObserver

    reason to not use IntersectionObserver

    I thought it was quite interesting reading your source code. You do not rely on IntersectionObserver.

    I was wondering what your thought process was creating this component and if you considered APIs like the IntersectionObserver or not, and for what reasons?


    opened by mesqueeb 1
  • Migrate to Vite builder

    Migrate to Vite builder

    This is a pre-step to Vue 3 migration, vuecli is no more supported, hence this PR to migrate to Vite.

    This PR may imply breaking changes in the use of the module in some scenarios.

    opened by Mikescops 0
  • Infinite scroll is made async and debounced

    Infinite scroll is made async and debounced

    It is likely that loading more content is an async call, so I made it a default.

    In case someone wants to do it with a sync function, they should return immediately in their code with Promise.resolve([content]) (depending on their implementation).

    Also i used computed data instead of refreshing all values everytime.

    enhancement hacktoberfest 
    opened by Mikescops 0
  • SSR nuxt

    SSR nuxt

    Hi does this work with nuxt / ssr? I've got

    document is not defined 

    Not sure if I implemented the virtual grid in the right way

      return styleElement
    function addStyle (obj /* StyleObjectPart */) {
      var update, remove
      var styleElement = document.querySelector('style[' + ssrIdKey + '~="' + + '"]')
      if (styleElement) {
        if (isProduction) {
          // has SSR styles and in production mode.
          // simply do nothing.
    bug need more info 
    opened by merijnponzo 11
  • Stability of scroll position, when changing the width

    Stability of scroll position, when changing the width

    First oft all thanks for the lib. I just tried it in the demo page and noticed. That if I rotate my phone, from vertical to horizontal I do not see a single picture I have Seen before. E.g. scrolling to section header 4 and rotating I had to scroll quite a bit to be back at the header.

    If it is possible I think it would be nice if the top left picture would stay in the top left field shown when changing the width. For languages which are read from right to legt I think it should be the top right picture which stays stable in the screen.

    opened by tacruc 4
  • v2.5.0(May 5, 2022)

    What's Changed

    • allow to use the scrolling container inside a div
    • child elements now have a class to target them
    • fix warning on component name

    New Contributors

    • @gaodeng made their first contribution in

    Full Changelog:

    Source code(tar.gz)
    Source code(zip)
  • v2.4.0(Feb 16, 2022)

    /!\ Potential breaking changes in the import of the module.

    As vuecli is deprecated, this version uses Vite to build the library. This is the first step into Vue3 migration.

    TS types are also included in this release.

    Some additional fixes are coming along.

    Kudos to those useful resources:

    Source code(tar.gz)
    Source code(zip)
  • v2.3.0(Dec 15, 2020)

  • v2.2.1(Oct 21, 2020)

  • v2.1.1(Oct 13, 2020)

    Breaking changes:

    • We don't handle storage of items list anymore, it should be passed as prop as of now. The updateFunction should now return a Promise that defines if the infinite scroll has reached the bottom.
    • We don't handle the offset increment anymore, it should be done by the parent component.

    New features:

    • Loading component prop can be set to display a component when the updateFunction is still running.
    • Debug prop can be set to display the debugging console logs.

    Dependencies are up to date.

    Source code(tar.gz)
    Source code(zip)
  • v1.2.2(Oct 8, 2020)

  • v1.2.1(Oct 7, 2020)

  • v1.2.0(Oct 7, 2020)

    Breaking change:

    • updateFunction is now async because it is likely you fetch the content asynchronously.


    • faster rendering with computed vars
    Source code(tar.gz)
    Source code(zip)
  • v1.1.1(Oct 5, 2020)

    New features:

    • customize even more the behavior of the grid by defining gaps, column number, windowing trigger...
    • customize the injected parameters to fit your needs!

    The Typescript support is also enhanced!

    Source code(tar.gz)
    Source code(zip)
  • v1.0.1(Oct 4, 2020)

Corentin Mors
Backend Dev @Dashlane #cybersecurity
Corentin Mors
Layoutit grid is a CSS Grid layout generator

Layoutit grid is a CSS Grid layout generator. Quickly draw down web pages layouts with our clean editor, and get HTML and CSS code to quickstart your next project.

Leniolabs_ 1.4k Jan 1, 2023
vue-products-grid is a responsive Vue component to create a products grid for ecommerce apps.

| vue-products-grid vue-products-grid is a responsive Vue component to create a products grid for ecommerce apps. Fully configurable with different op

Antonio 4 Oct 13, 2022
Vue-grid-layout is a grid layout system, like Gridster, for Vue.js.

vue-grid-layout vue-grid-layout is a grid layout system, like Gridster, for Vue.js. Heavily inspired by React-Grid-Layout Current version: 2.3.9 (Supp

Danny Funkat 0 Feb 22, 2022
🧮 Generate basic CSS Grid code to make dynamic layouts!

CSS Grid Generator Site: This project is a way for people to use CSS Grid features quickly to create dynamic la

Sarah Drasner 4.5k Dec 31, 2022
Proyecto de grado del SENA, creación de un objeto virtual de aprendizaje para el área de deportes.

OVA - Ejecución de programas deportivos Objeto virtual de aprendizaje para el estudio del área de deportes del SENA. Integrantes Edwin Jesús Páez Rued

Edwin J. Páez 1 Jan 3, 2022
Vue Virtual Keyboard - Simple-keyboard Vue.js Demos

This is a repository for simple-keyboard's Vue.js demos Have an issue or question? Please post it in the main re

simple-keyboard 39 Oct 12, 2022
A vuejs grid with draggable and resizable boxes

dnd-grid A vuejs grid with draggable and resizable boxes Demo page The demo requires Vue >= 2.3.0 because of the ":layout.sync" feature The components

null 307 Nov 11, 2022
Flexbox based responsive fraction grid system

vue-fraction-grid Flexbox based responsive fraction grid system for Vue.js Live Demo and Full Documentation <container> <grid vertical="middle" :rwd

Bartłomiej Kozal 87 Dec 20, 2021
Responsive grid system based on Bootstrap for Vue

Vue Grid Responsive Responsive grid system based on Bootstrap for Vue. • • Installation NPM vue 2.0 npm i vue-grid-responsive // OR yarn add vue-grid-

André Lins 27 Sep 11, 2022
⚡️ Blazing fast scrolling for any amount of data

vue-virtual-scroller Blazing fast scrolling of any amount of data | Live demo | Video demo Sponsors Table of contents Installation Usage RecycleScroll

Guillaume Chau 7.6k Jan 4, 2023
Popular layouts and patterns made with Tailwind CSS

Popular layouts and patterns made with Tailwind CSS

LaLoka Labs 102 Dec 27, 2022
A draggable and resizable grid layout, for Vue.js.

vue-grid-layout Documentation Website What is Vue Grid Layout? vue-grid-layout is a grid layout system, like Gridster, for Vue.js. Heavily inspired by

JBay Solutions 6k Jan 4, 2023
Auto responsive grid layout library for Vue.

autoresponsive-vue Auto responsive grid layout library for Vue. Examples Live demo & docs: Installation $ npm i

达峰的夏天 139 Dec 23, 2022
A flexbox grid system.

VueFlex A flexbox grid system. demo Try it out! setup npm npm install @seregpie/vueflex Register the components globally. import Vue from 'vue'; impor

Sergej Sintschilin 13 Oct 3, 2020
Lightweight set of functional grid components

vue-grid-styled Vue.js port of @jxnblk's React library, grid-styled Installation yarn add vue-grid-styled Default Theme // Breakpoints const breakpoin

Matt Rothenberg 17 Aug 23, 2022
grid layout,support flex

simple-grid a simple grid layout(Vue Component) Installation use npm $ npm i simple-xgrid --save import Grid from 'simple-xgrid' import 'simple-xgrid

zhoulin 25 Nov 24, 2022
🧙‍♂️🔌 Responsive Magic Grid for Vue

Vue-Magic-Grid This is a Vue.js port of @e-oj's Magic Grid. Please check the /test folder for a example. If you use images, make sure they have a set

Emmanuel Olaojo 172 Aug 17, 2022
Simple, Light-weight and Flexible Vue.js component for grid layout.

vue-grd Simple, Light-weight and Flexible Vue.js component for grid layout. Vue.js port of grd. Install npm install --save vue-grd Usage You can use <

Shogo Sensui 42 Nov 24, 2022
Responsive, Draggable & Resizable Dashboard (Grid) for Vue

vue-responsive-dash A Responsive, Draggable & Resizable Dashboard (grid) made with vue and typescript. Inspired by React-Grid-Layout & Vue-Grid-Layout

Ben Sladden 247 Dec 23, 2022