[Solved] Scheduler becomes unresponsive

3 Answers 28 Views
Scheduler
Kumeri
Top achievements
Rank 1
Iron
Veteran
Iron
Kumeri asked on 09 Sep 2026, 04:41 AM

The scheduler becomes unresponsive when there are a large number of events. (>3000 entries in the customer) is not feasible.

The browser again becomes unresponsive and displays the "This page isn't responding" message.

What is the maximum number of events the Kendo scheduler can display?

3 Answers, 1 is accepted

Sort by
0
Zornitsa
Telerik team
answered on 11 Sep 2026, 08:06 AM

Hi Kumeri,

There is no documented or hard-coded maximum number of events that the Kendo UI for Angular Scheduler can display. The practical limit depends on several factors, such as browser performance and memory management, user device specifications, complexity of event templates and resource configuration, the number of events, and the Scheduler view type.

In general, rendering thousands of events at once can lead to significant performance issues, including browser unresponsiveness. This is because the Scheduler currently renders all events and resources in the DOM simultaneously - there is no built-in virtualization or virtual scrolling for Scheduler events or resources.

With the above being said, to optimize performance in the Scheduler with large number of events, the developer can implement the approach suggested in the following article:

To be more comprehensive, the above article explains how to load events in smaller chunks when the current date range changes by handling the dateChange event of the component. In that way, the performance of the Scheduler can be significantly improved with large datasets by only loading events that should be currently visible.

In this line of thought, there is also an existing feature request about virtualization and paging for the Scheduler, for which I added a vote on your behalf:

Feel free to follow the above feature request in order to track the progress of its implementation.

I hope the provided information is helpful. Let me know if any further questions arise.

Regards,
Zornitsa
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Jake
Top achievements
Rank 1
commented on 29 Sep 2026, 12:13 PM

That makes a lot more sense. With 3000+ events in one resource group plus custom event, slot, header and toolbar templates, I’d expect the templates and the repeated style/function calls to become a much bigger factor than the raw number of records alone.

I’d probably profile the rendering with the browser performance tools and check how often getSlotClass and getEventStyles are being called, especially if they do any non-trivial work. It may also be worth temporarily removing the custom templates one by one to see which one has the biggest impact.

If the basic Scheduler with 3000 events performs reasonably well but the full version becomes unresponsive, that should help narrow down whether the bottleneck is the Scheduler rendering itself or the custom templates/styling around it.

0
Kumeri
Top achievements
Rank 1
Iron
Veteran
Iron
answered on 14 Sep 2026, 05:15 AM
We already have this load events on demand applied. We are only loading data for the current view. We create a filter for the server call and load only that specific data from the dateChange event return date range, but in our scenario it is a week view, and we have 3000+ records in that view that we need to display. Are there any other suggestions to improve performance, or any demo/ example with that amount of data in a week view u can share with us so we can have a look on that
Zornitsa
Telerik team
commented on 16 Sep 2026, 03:06 PM

Hi Kumeri,

Thank you for clarifying that all 3,000+ events fall within the same visible week. In that case, loading by the dateChange range is already doing what it can, but the Scheduler still has to create and position every appointment in that week.

On that note, there is no official maximum or supported benchmark, because the result also depends on how many events overlap, resource grouping, recurring events, custom templates, the browser, and the client device.

In this line of thought, I also tested a local Week-view example with 3,000 generated events in the following StackBlitz example:

As it can be observed in the above example, although the Scheduler renders the dataset, the event columns become extremely narrow, and the individual appointments are not readable or practical to interact with. The exact result will, of course, vary with the event distribution; however, this raises a question about the intended user workflow, i.e., could you please clarify what the specific expectation is when rendering all 3,000 events in a single Week view - are the events also not readable on your side, or am I missing something in replicating the Scheduler scenario that should be achieved?

In particular, could you clarify the following:

  • Are the events spread throughout the week, or do many of them overlap within the same time periods?
  • Are events duplicated across grouped resources or assigned to multiple resources?
  • Would filtering by resource, team, location, or category meet your requirements?

Providing such information will help me better understand the exact end goal both in terms of UI and UX when rendering 3000+ events in one Scheduler view, and thus I will be able to provide more valuable assistance on the matter (share more suitable suggestions for optimizing the rendering).

What I can currently suggest as the most effective next step (based on the assumption that the above example fits your scenario) is to reduce the number of appointments rendered at one time. If the workflow permits it, you could consider one or more of the following:

Please observe the provided information and share more details about your requirements and the desired end result. I am looking forward to your reply.

Regards,
Zornitsa
Progress Telerik

0
Kumeri
Top achievements
Rank 1
Iron
Veteran
Iron
answered on 22 Sep 2026, 06:40 AM

Hi, in the mentioned scenarios, it is a calendar with groups available. So there are resources, and we are using one resource to group the calendar. In the mentioned scenarios, all 3000+ events are mainly in one group, but in different scenarios it can be divided among groups. And the scheduler is not as simple as the one defined in the example u are shared, where we are only sending the array. We have several templates defined, and we are sending CSS classes for styling. 


  <kendo-scheduler #kendoScheduler
                [class.hide-footer]="!showWorkHours"
                [class.slot-duration-1440]="isSchedulerSlotDuration1440"
                [class.has-timezone-headers]="showTimezoneHeaders && timezoneSettings && timezoneSettings.length > 0"
                [loading]="isLoading"
                [kendoSchedulerBinding]="schedulerEvents"
                [editable]="schedulerEditableSettings"
                [(selectedDate)]="selectedDate"
                [selectable]="calendarSelectable"
                [isSlotSelected]="isSlotSelected"
                [timezone]="timezone"
                [weekStart]="firstDay ? firstDay : 0"
                [workWeekStart]="workWeekStart"
                [workWeekEnd]="workWeekEnd"
                [workDayStart]="workDayStart"
                [workDayEnd]="workDayEnd"
                [slotDuration]="slotDuration"
                [slotDivisions]="1"
                [showWorkHours]="showWorkHours"
                [allDaySlot]="true"
                [slotClass]="getSlotClass"
                [eventStyles]="getEventStyles"
                [resources]="resources"
                [group]="groups"
                [(selectedViewIndex)]="selectedViewIndex"
                (dateChange)="onDateChange($event)"
                (navigate)="onNavigate($event)"
                (schedulerResize)="onSchedulerResize($event)"
                (slotDragStart)="onSlotDragStart($event)"
                (slotDrag)="onSlotDrag($event)"
                (dragStart)="onEventDragStart($event)"
                (dragEnd)="onEventDragEnd($event)"
                (resizeStart)="onEventResizeStart($event)"
                (resizeEnd)="onEventResizeEnd($event)">

And also we are using all these templates as well

kendoSchedulerEventTemplate

kendoSchedulerGroupHeaderTemplate

kendoSchedulerAllDayEventTemplate

kendoSchedulerMonthDaySlotTemplate

kendoSchedulerTimeSlotTemplate

kendoSchedulerDateHeaderTemplate

kendoSchedulerToolbarTemplate
<ng-template kendoSchedulerEventTemplate let-event="event" let-resources="resources">
                    <div class="event"
                    [title]="event.title"
                    [innerHTML]="getSanitizedHtml(event.description)"
                    (click)="openDetailsCard($event, event.id)">
                </div>
                </ng-template>

                <ng-template kendoSchedulerGroupHeaderTemplate let-resource="resource">
                    <div class="grouping-text" style="display: inline-block; vertical-align: top; margin-top: .25rem">{{resource.text}}</div>
                    <div *ngIf="hasSummaryCard" class="card-icon-container" style="display: inline-block; vertical-align: top; margin-top: 0.1rem" id="{{resource.value}}"
                    (click)="openSummaryCard($event, resource.value)"><i class="information-button icon-card"></i></div>
                </ng-template>

                <ng-template kendoSchedulerAllDayEventTemplate let-event="event" let-resources="resources" let-date="date">
                    <div *ngIf="calendarSelectable && lastSelectedSlot(date, resources)" class="timeslot-new-button-month" (click)="addButtonClicked($event)"><span class="icon-new"></span></div>
                    <div class="event"
                    [title]="event.title"
                    [innerHTML]="getSanitizedHtml(event.description)"
                    (click)="openDetailsCard($event, event.id)">
                </div>
                </ng-template>

                <!-- Slot Template -->
                <ng-template kendoSchedulerMonthDaySlotTemplate let-date="date" let-resources="resources">
                    <div class="month-slot-container">
                    <div *ngIf="calendarSelectable && lastSelectedSlot(date, resources)" class="timeslot-new-button-month" (click)="addButtonClicked($event)"><span class="icon-new"></span></div>
                    <div class="month-slot-header">
                        <div *ngIf="getWeekNumberForMonthSlot(date) as weekLabel" class="week-square" (click)="onMoreEventsClick(date)">{{weekLabel}}</div>
                        <span class="k-link k-nav-day" [class.calendar-today-timeslot]="isToday(date)">{{date | date:'dd'}}</span>
                    </div>
                    </div>
                </ng-template>

                <ng-template kendoSchedulerTimeSlotTemplate let-date="date" let-resources="resources">
                    <div *ngIf="calendarSelectable && lastSelectedSlot(date, resources)" class="timeslot-new-button" (click)="addButtonClicked($event)"><span class="icon-new"></span></div>
                </ng-template>

                <!-- Date Header Template -->
                <ng-template kendoSchedulerDateHeaderTemplate let-date="date">
                    <span class="k-link k-nav-day">{{date | date:'EEEE'}}, {{date | date:'MMMM d'}}</span>
                </ng-template>

                <!-- Toolbar Template -->
                <ng-template kendoSchedulerToolbarTemplate let-dateRange="dateRange" let-selectedView="selectedView" let-selectedDate="selectedDate">
                    <div *ngIf="!isCustomTimelineView" class="calendar-toolbar-wrapper">
                        <div class="calendar-toolbar-left">
                            <div kendoSchedulerToolbarNavigation></div>
                            <span>{{getTitleWeekNumber(selectedView.name, dateRange)}}</span>
                        </div>
                        <div kendoSchedulerToolbarViewSelector
                        [toolbarWidth]="toolbarWidth"
                        [responsiveBreakpoint]="960"></div>
                    </div>
                </ng-template>

 

 

Zornitsa
Telerik team
commented on 24 Sep 2026, 03:10 PM

Hi Kumeri,

Thank you for providing the full configuration. Indeed, given this configuration, it is expected that the production Scheduler performs more work than the simpler example I gave in my previous reply. Each resource group adds its own slot grid, and events assigned to multiple resource values can be rendered in multiple groups. In addition, the custom event and slot logic is evaluated across thousands of appointments and slots.

On that note, apart from the large number of events, what I notice as the most likely application-level cost is getSanitizedHtml(event.description), because it is called from both event templates for every rendered appointment. The getEventStyles, getSlotClass, isSlotSelected, and lastSelectedSlot methods can also add substantial work if they perform array searches, create objects, call services, or modify state. The group header, date header, and toolbar templates have far fewer instances and are less likely to be part of the main cause.

To identify the main bottleneck, I recommend testing the same 3,000 events and resource grouping as follows:

  • Preprocess the sanitized description when mapping the server data instead of calling a sanitization method from the template.
  • Temporarily remove the custom templates, styling callbacks, selection logic, and editing features.
  • Add a minimal plain-text event template and compare the rendering time.
  • Restore the remaining callbacks and features one at a time to identify which one has the largest impact.

This comparison will separate the base issue of laying out 3,000 appointments from the potential additional performance cost of the application templates and callbacks.

Nevertheless, the earlier simpler test in the StackBlitz example still raises a usability concern - when thousands of appointments overlap in one resource group, the event columns become too narrow to read or select individually. Thus, could you describe the exact action users need to perform in that state? For example, do they need to inspect and open every individual event, compare availability, or see only counts or status by time period? If individual interaction is required, filtering by resource/category will likely be necessary even after the callback code is optimized.

With the above being said, it is important to clarify that in the current state of the Scheduler, where virtualization is still not available as a built-in feature, even after reducing the callback and template overhead, performance issues are still expected when 3,000 appointments are rendered in a single view. The above optimization suggestions may improve the performance, but they cannot eliminate the fact that a very large number of events are rendered in the DOM at once. Rendering this volume at once would require event virtualization, which the Scheduler does not currently provide.

I hope the provided information proves to be helpful for your scenario.

Regards,
Zornitsa
Progress Telerik

Tags
Scheduler
Asked by
Kumeri
Top achievements
Rank 1
Iron
Veteran
Iron
Answers by
Zornitsa
Telerik team
Kumeri
Top achievements
Rank 1
Iron
Veteran
Iron
Share this question
or