New to Kendo UI for AngularStart a free 30-day trial

Locking Grid Header on Top While Scrolling the Page

Updated on Jan 20, 2026

Environment

ProductProgress® Kendo UI for Angular Grid

Description

I want to lock the header of the Kendo UI for Angular Grid so that it remains visible while scrolling up or down the page. Currently, the header disappears when scrolling the page vertically, which creates confusion for users trying to interpret the data.

This Knowledge Base article also answers the following questions:

  • How to freeze the header of the Grid while scrolling?
  • How to prevent the header from disappearing in Kendo UI for Angular Grid?
  • How to make the header of the Angular Grid sticky?

Solution

To achieve this functionality, you can implement custom logic using Angular best practices with Renderer2 for DOM manipulation. This approach calculates the scroll position and toggles a custom class for the Grid header based on whether the scroll position is within the Grid's boundaries.

Follow these steps to achieve the full implementation:

  1. Import the necessary Angular services and lifecycle hooks in your component.

    typescript
    import { Component, Renderer2, ElementRef, AfterViewInit } from '@angular/core';
  2. Inject Renderer2 and ElementRef through the constructor and implement AfterViewInit to cache DOM elements after view initialization.

    typescript
    export class AppComponent implements AfterViewInit {
        private gridElement?: HTMLElement;
        private headerElement?: HTMLElement;
    
        constructor(private renderer: Renderer2, private elementRef: ElementRef) {}
    
        ngAfterViewInit(): void {
            // Cache DOM elements after view initialization for better performance
            this.gridElement = this.elementRef.nativeElement.querySelector('.k-grid');
            this.headerElement = this.elementRef.nativeElement.querySelector('.k-grid-header');
        }
    }
  3. Create a scroll event handler that uses the cached elements and Renderer2 for DOM manipulation.

    typescript
    public onContainerScroll(event: Event): void {
        if (!this.gridElement || !this.headerElement) {
            return;
        }
    
        const container = event.target as HTMLElement;
        const scrollTop = container.scrollTop;
        const gridTop = this.gridElement.offsetTop;
        const gridBottom = gridTop + this.gridElement.clientHeight - this.headerElement.clientHeight;
    
        if (scrollTop < gridTop || scrollTop > gridBottom) {
            this.renderer.removeClass(this.headerElement, 'fixed-header');
            this.renderer.setStyle(this.headerElement, 'width', 'auto');
        } else if (scrollTop >= gridTop && scrollTop <= gridBottom) {
            this.renderer.addClass(this.headerElement, 'fixed-header');
            this.renderer.setStyle(this.headerElement, 'width', `${this.gridElement.clientWidth}px`);
        }
    }

    This implementation uses Renderer2 methods for safe DOM manipulation. The addClass and removeClass methods toggle the fixed-header CSS class based on the scroll position, while setStyle dynamically adjusts the header width to match the Grid's width when fixed or resets it to 'auto' when not fixed. The logic ensures the header appears fixed only when the Grid content is visible within the scroll boundaries.

  4. Bind the scroll event handler to your scrollable container in the template.

    html
    <div class="demo-container" (scroll)="onContainerScroll($event)">
        <kendo-grid [data]="gridData">
            <!-- Grid columns -->
        </kendo-grid>
    </div>
  5. Define suitable CSS styles that will be applied when the fixed-header class is added to the Grid header.

    css
    .fixed-header {
        position: fixed;
        top: 0;
        z-index: 1;
    }

The following example demonstrates the suggested approach in action.

The demo below uses a custom scrollable container for demonstration purposes in an iframe environment. In a real application, you can use the window:scroll event as shown in the code snippets above.

Change Theme
Theme
Loading ...

See Also

In this article
EnvironmentDescriptionSolutionSee Also
Not finding the help you need?
Contact Support