# Infinite Scrolling (JavaScript Scheduler) | DayPilot Pro for JavaScript Demo

> Scroll horizontally to extend the timeline. Auto adjusts the buffer to the available width. Settings apply when changed. Read more about [infinite scrolling](https://doc.daypilot.org/scheduler/infinite-scrolling/).

## Links

- Canonical HTML: /demo/scheduler/infinite.html
- Source HTML folder: /demo/scheduler/
- Catalog root: /demo/
- Catalog: /demo/llms.txt

## Source

### Inline demo script 1

```javascript
const app = {
            events(viewport) {
                const list = [];
                const origin = new DayPilot.Date("2026-01-01");
                const interval = 3;
                const first = Math.floor(new DayPilot.Duration(viewport.start.ticks - origin.ticks).totalDays() / interval) - 1;
                const last = Math.ceil(new DayPilot.Duration(viewport.end.ticks - origin.ticks).totalDays() / interval);
                for (let slot = first; slot <= last; slot++) {
                    for (let row = 0; row < dp.resources.length; row++) {
                        const from = origin.addDays(slot * interval + row % 3);
                        list.push({id: row + ":" + from.toString(), resource: "R" + row,
                            start: from, end: from.addDays(2),
                            text: ["Planning", "Delivery", "Review", "Preparation"][row % 4],
                            backColor: row % 2 ? "#dcfce7" : "#dbeafe", barColor: row % 2 ? "#16a34a" : "#2563eb"});
                    }
                }
                return list;
            },
            read() {
                const mode = document.getElementById("scrolling-mode").value;
                return {infiniteScrollingEnabled: mode === "Auto" ? "Auto" : mode === "true",
                    days: Number(document.getElementById("range-days").value),
                    infiniteScrollingStepDays: Number(document.getElementById("step-days").value),
                    infiniteScrollingMargin: Number(document.getElementById("margin").value)};
            },
            apply() {
                const form = document.getElementById("infinite-settings");
                if (!form.reportValidity()) return;
                const options = this.read();
                const anchor = dp.getViewport().start;
                const message = document.getElementById("settings-message");
                try {
                    if (!options.infiniteScrollingEnabled) options.startDate = anchor.getDatePart();
                    dp.update(options);
                    dp.scrollTo(anchor);
                    this.previous = options;
                    message.hidden = true;
                }
                catch (error) {
                    dp.update(this.previous);
                    dp.scrollTo(anchor);
                    message.textContent = error.message || String(error);
                    message.hidden = false;
                }
            },
            showFields() {
                const mode = document.getElementById("scrolling-mode").value;
                document.getElementById("manual-settings").hidden = mode === "Auto";
                document.getElementById("step-setting").hidden = mode === "false";
                document.getElementById("margin-setting").hidden = mode === "false";
                document.getElementById("settings-help").hidden = mode === "false";
            },
            init() {
                this.previous = this.read();
                const form = document.getElementById("infinite-settings");
                form.addEventListener("change", () => {this.showFields(); this.apply();});
                form.addEventListener("submit", event => {event.preventDefault(); this.apply();});
                const scroll = date => {
                    try {dp.scrollTo(date);}
                    catch (error) {
                        const message = document.getElementById("settings-message");
                        message.textContent = error.message || String(error); message.hidden = false;
                    }
                };
                for (const [id, date] of [["jan1", "2026-01-01"], ["jun1", "2026-06-01"], ["nov1", "2026-11-01"]]) {
                    document.getElementById(id).addEventListener("click", () => scroll(date));
                }
                document.getElementById("minus").addEventListener("click", () => scroll(dp.getViewport().start.addMonths(-1)));
                document.getElementById("plus").addEventListener("click", () => scroll(dp.getViewport().start.addMonths(1)));
                document.getElementById("today").addEventListener("click", () => scroll(DayPilot.Date.today()));
                document.getElementById("scroll-date-go").addEventListener("click", () => {
                    const field = document.getElementById("scroll-date");
                    if (field.value && field.reportValidity()) scroll(field.value);
                });
            }
        };
        const dp = new DayPilot.Scheduler("dp", {
            startDate: "2026-10-01", scale: "Day", cellWidth: 40,
            timeHeaders: [{groupBy: "Month", format: "MMMM yyyy"}, {groupBy: "Day", format: "d"}],
            infiniteScrollingEnabled: "Auto", days: 300,
            infiniteScrollingStepDays: 70, infiniteScrollingMargin: 200,
            rowHeaderWidth: 180, heightSpec: "Fixed", height: 360,
            resources: Array.from({length: 12}, (_, i) => ({id: "R" + i, name: "Resource " + (i + 1)})),
            dynamicLoading: true, scrollDelayEvents: 0,
            eventMoveHandling: "Disabled", eventResizeHandling: "Disabled", timeRangeSelectedHandling: "Disabled",
            onScroll: args => {args.events = app.events(args.viewport); args.loaded();}
        });
        dp.init();
        app.init();
```

