# Progressive Time Headers (JavaScript Gantt Chart) | DayPilot Pro for JavaScript Demo

> Explore a project across a long timeline. Compare [progressive time header rendering](https://doc.daypilot.org/gantt/progressive-time-header-rendering/) on and off, then jump between project phases. Progressive rendering prepares headers as you scroll.

## Links

- Canonical HTML: /demo/gantt/timeheaderprogressive.html
- Source HTML folder: /demo/gantt/
- Catalog root: /demo/
- Catalog: /demo/llms.txt

## Source

### Inline demo script 1

```javascript
const dp = new DayPilot.Gantt("dp", {
            startDate: "2026-01-01",
            days: 365,
            scale: "Hour",
            cellWidth: 44,
            timeHeaders: [
                {groupBy: "Month", format: "MMMM yyyy"},
                {groupBy: "Day", format: "ddd d"},
                {groupBy: "Hour", format: "h tt"}
            ],
            progressiveTimeHeaderRendering: true,
            columns: [{title: "Project phase", property: "text", width: 220}],
            rowHeaderWidthAutoFit: false,
            heightSpec: "Auto",
            taskMoveHandling: "Disabled",
            taskResizeHandling: "Disabled",
            rowMoveHandling: "Disabled",
            linkCreateHandling: "Disabled"
        });
        dp.init();

        const app = {
            presets: {
                month: {days: 31, scale: "Day", cellWidth: 60},
                year: {days: 365, scale: "Hour", cellWidth: 44},
                threeYears: {days: 1096, scale: "Hour", cellWidth: 44}
            },
            init() {
                document.getElementById("enabled").addEventListener("change", ev => {
                    dp.update({progressiveTimeHeaderRendering: ev.target.checked});
                });
                document.getElementById("preset").addEventListener("change", () => this.loadTimeline());
                document.querySelectorAll("#gantt-time-headers [data-jump]").forEach(button => {
                    button.addEventListener("click", () => {
                        const fraction = Number(button.dataset.jump);
                        dp.scrollTo(dp.startDate.addDays(Math.floor(dp.days * fraction)));
                    });
                });
                this.loadTimeline();
            },
            loadTimeline() {
                const preset = this.presets[document.getElementById("preset").value];
                const start = new DayPilot.Date("2026-01-01");
                const timeHeaders = [
                    {groupBy: "Month", format: "MMMM yyyy"},
                    {groupBy: "Day", format: "ddd d"}
                ];
                if (preset.scale === "Hour") {
                    timeHeaders.push({groupBy: "Hour", format: "h tt"});
                }
                const middle = Math.floor(preset.days / 2);
                const tasks = [
                    {id: "planning", text: "Planning", start, end: start.addDays(3), complete: 100},
                    {id: "design", text: "Design review", start: start.addDays(3), end: start.addDays(6), complete: 80},
                    {id: "delivery", text: "First delivery", start: start.addDays(middle), end: start.addDays(middle + 3), complete: 40},
                    {id: "review", text: "Delivery review", start: start.addDays(middle + 3), end: start.addDays(middle + 5), complete: 0},
                    {id: "handover", text: "Final handover", start: start.addDays(preset.days - 3), end: start.addDays(preset.days), complete: 0}
                ];
                dp.update({...preset, startDate: start, timeHeaders, tasks});
                dp.scrollTo(start);
            }
        };
        app.init();
```

