---
title: "Javascript Timeline Virtual Scrolling Example | Mobiscroll"
component: "Timeline"
framework: "JavaScript"
library_version: "6.1.5"
url: "https://demo.mobiscroll.com/javascript/timeline/load-events-on-scroll"
---

# Virtual Scrolling - JavaScript Timeline demo

Load events on scroll with a virtualized Javascript Timeline — only the visible date range is fetched, keeping large resource timelines responsive. Plain JS api for usage everywhere.

- [Live demo](https://demo.mobiscroll.com/javascript/timeline/load-events-on-scroll)
- [View code on GitHub](https://github.com/acidb/mobiscroll-demos-javascript/tree/main/src/demos/eventcalendar/timeline/load-events-on-scroll)
- This demo in other frameworks: [jQuery](https://demo.mobiscroll.com/jquery/timeline/load-events-on-scroll.md), [Angular](https://demo.mobiscroll.com/angular/timeline/load-events-on-scroll.md), [React](https://demo.mobiscroll.com/react/timeline/load-events-on-scroll.md), [Vue](https://demo.mobiscroll.com/vue/timeline/load-events-on-scroll.md)

## Description

The timeline view is virtualized which means that the markup is being generated and maintained on the fly. Navigating both vertically and horizontally through scrolling fires the [`onVirtualLoading`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onVirtualLoading) lifecycle event which can be used to load the data on scroll rather than load everything on initial page rendering.

This dramatically improves performance in case of a large event count since not all data is loaded in memory from start.

**Looking to load resources on scroll?** [Check out this example →](https://demo.mobiscroll.com/javascript/timeline/load-resources-on-scroll)

## What this demo shows

- A desktop month timeline with days arranged horizontally and resources listed as rows on the left.
- **Loading events on scroll** A `Loading events...` toast appears at the bottom center of the timeline on initial load, month change, and vertical or horizontal timeline scrolling.
- **Virtual loading** Scrolling through the virtualized timeline fires the `onVirtualLoading` lifecycle event, which can be used to load events for the visible date range instead of loading all events during initial rendering.
- **Header navigation** The month and year label opens date navigation, the previous and next arrows move between months, and the Today button returns to the current date.
- **Month view** The strip below the header shows the days of the selected month, with the current date highlighted.
- **Timeline grid** The timeline displays hourly columns from 12 AM to 12 PM.
- **Resources** Multiple resources are shown as separate timeline rows.
- **Current time** A vertical blue line with a time label marks the current time.
- **Hover behavior** Hovering over the time grid shows a time indicator that follows the cursor in 15-minute increments.
- **Event cards** Events appear as colored cards with a colored stripe on the left, the event title in bold, and the exact start and end time displayed below the title.
- **Date positioning** Events are positioned by their assigned resource and exact date range.
- **Event interaction** Events highlight on hover and show drag and resize handles for repositioning or changing duration.
- **Event selection** Clicking an event selects and highlights it.
- **Event creation** New events can be created by double-clicking the timeline or by clicking and dragging across a time range.
- **Scrolling** The timeline supports horizontal and vertical scrolling for navigating through time and resources.

## Best for

- **Large event datasets** Loading events only for the visible timeline range instead of loading every event up front.
- **Resource scheduling** Showing many resources in a timeline where users need to scroll vertically through rows and horizontally through dates.
- **Long-range planning views** Keeping month-based timeline navigation responsive while users move across a wider date range.
- **Performance-sensitive scheduling apps** Reducing initial page load work when the full event set is too large to keep in memory from the start.

## API used in this demo

- [`theme`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-theme) - option
- [`themeVariant`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-themeVariant) - option
- [`view`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-view) - option
- [`resources`](https://mobiscroll.com/docs/javascript/eventcalendar/api#opt-resources) - option
- [`onVirtualLoading`](https://mobiscroll.com/docs/javascript/eventcalendar/api#event-onVirtualLoading) - event
- [`setEvents`](https://mobiscroll.com/docs/javascript/eventcalendar/api#method-setEvents) - method

## Code

### JS

```js
mobiscroll.setOptions({
  theme: 'ios',
  themeVariant: 'light'
});

mobiscroll.eventcalendar('#demo-load-events-on-scroll', {
  view: {
    timeline: {
      type: 'month',
      resolutionHorizontal: 'hour',
    },
  },
  resources: [
    { id: 1, name: 'Resource 1', color: '#FF5733' },
    { id: 2, name: 'Resource 2', color: '#33FF57' },
    { id: 3, name: 'Resource 3', color: '#3357FF' },
    { id: 4, name: 'Resource 4', color: '#FF33A6' },
    { id: 5, name: 'Resource 5', color: '#FFC300' },
    { id: 6, name: 'Resource 6', color: '#DAF7A6' },
    { id: 7, name: 'Resource 7', color: '#581845' },
    { id: 8, name: 'Resource 8', color: '#900C3F' },
    { id: 9, name: 'Resource 9', color: '#C70039' },
    { id: 10, name: 'Resource 10', color: '#FF5733' },
    { id: 11, name: 'Resource 11', color: '#33FFBD' },
    { id: 12, name: 'Resource 12', color: '#FFC300' },
    { id: 13, name: 'Resource 13', color: '#FF33F6' },
    { id: 14, name: 'Resource 14', color: '#33FF57' },
    { id: 15, name: 'Resource 15', color: '#33A6FF' },
    { id: 16, name: 'Resource 16', color: '#DAF7A6' },
    { id: 17, name: 'Resource 17', color: '#581845' },
    { id: 18, name: 'Resource 18', color: '#900C3F' },
    { id: 19, name: 'Resource 19', color: '#C70039' },
    { id: 20, name: 'Resource 20', color: '#FF33F6' },
    { id: 21, name: 'Resource 21', color: '#FF5733' },
    { id: 22, name: 'Resource 22', color: '#33FF57' },
    { id: 23, name: 'Resource 23', color: '#3357FF' },
    { id: 24, name: 'Resource 24', color: '#FF33A6' },
    { id: 25, name: 'Resource 25', color: '#FFC300' },
  ],
  onVirtualLoading: function (args, inst) {
    var start = mobiscroll.formatDate('YYYY-MM-DD', args.viewStart);
    var end = mobiscroll.formatDate('YYYY-MM-DD', args.viewEnd);
    mobiscroll.getJson(
      'https://trial.mobiscroll.com/load-data-scroll/?start=' + start + '&end=' + end,
      function (data) {
        inst.setEvents(data.events);
        mobiscroll.toast({
          message: 'Loading events...',
          duration: 1000,
        });
      },
      'jsonp',
    );
  },
});
```

### HTML

```html
<div id="demo-load-events-on-scroll"></div>
```

## Implementation notes

- Use `timeline: { type: 'month', resolutionHorizontal: 'hour' }` - a month view with hourly columns, creating a wide horizontally scrollable grid.
- Define 25 resources (Resource 1-25) with varied colors.
- **Scroll-triggered loading** is driven by `onVirtualLoading`, which fires whenever the user scrolls horizontally or vertically through the virtualized timeline. Inside the handler, read `args.viewStart` and `args.viewEnd` to get the currently visible time window, then build the API URL:
  ```
  https://trial.mobiscroll.com/load-data-scroll/?start=YYYY-MM-DD&end=YYYY-MM-DD
  ```
  Format both dates with `formatDate('YYYY-MM-DD', args.viewStart)` and `formatDate('YYYY-MM-DD', args.viewEnd)`.
- The endpoint returns a JSONP object with an `events` property (not a plain array). Read `data.events` after the fetch.
- Fetch via JSONP using `getJson(url, callback, 'jsonp')`. The endpoint returns an object - read `data.events`, not the raw response. After loading, React/Angular/Vue: assign `data.events` to the state/property bound to the `data` prop. JS/jQuery (imperative API): call `inst.setEvents(data.events)`. Then show a `Toast` with `duration: 1000`.

## Run it in your project

1. If not signed up yet, or don't own a license, you can [start a free trial](https://mobiscroll.com/starttrial).

2. Clone the repository:

   ```
   git clone https://github.com/acidb/mobiscroll-demos-javascript.git
   ```

3. If not installed yet, install the Mobiscroll CLI from NPM:

   ```
   npm install -g @mobiscroll/cli
   ```

4. Config Mobiscroll - open a terminal window in the root directory and run:

   ```
   mobiscroll config javascript
   ```

5. Install dependencies - open a terminal window in the root directory and run:

   ```
   npm install
   ```

6. Run the project:

   ```
   npm run dev
   ```

On a trial, add `--trial` to the config command: `mobiscroll config javascript --trial`.

Running a demo locally requires a Mobiscroll trial or a license; setup is per framework at https://mobiscroll.com/docs/javascript/getting-started/installation

## Related demos

- Previous: [Load Events on Demand](https://demo.mobiscroll.com/javascript/timeline/load-events-on-demand.md) - Load timeline events on demand — fetch only the visible time range from a remote or local source using the Javascript Timeline.
- Next: [Load Resources on Demand](https://demo.mobiscroll.com/javascript/timeline/load-resources-on-demand.md) - Build hierarchical resource scheduling interfaces with on-demand data loading — the Javascript Timeline fetches child resources.
