Click here to Skip to main content
15,860,859 members
Articles / Web Development / CSS

Freezing ASP.NET GridView Header With JavaScript and CSS

Rate me:
Please Sign up or sign in to vote.
4.55/5 (14 votes)
31 Oct 2008CPOL2 min read 193.3K   4.3K   69   31
Freeze an ASP.NET GridView header using JavaScript and CSS.

FreezeGridViewHeader

Introduction

Frozen header for an ASP.NET GridView is a common requirement for web developers nowadays. For usability reasons, frozen or fixed headers are a must for data viewing controls like DataGrid, GridView, or a raw HTML table etc. You must have observed that, in Excel, you can freeze the header cells of your spread sheet. When you scroll down, the headers are always visible, making your sheet more readable. The same effect is often needed in a GridView control, especially if you are displaying many records at a time. In this article, I will explain a technique that will allow you to achieve this with ease.

Conceptual Discussions

We all know that after executing the server-side code, raw HTML is returned to the browser, and the browser just shows the HTML. Obviously, a GridView needs to be converted to an HTML table. So, we need to do some customizations on the returned table to reach our goal. There are some steps to do that customization that are mentioned below:

  1. Take away the table row which usually represents the header and assign it to a newly created “<THEAD>” tag.
  2. Make the rest of table/grid row scrollable by limiting the height of the table and adding the “overflow: auto” attribute inside both “<TBODY>” and “<DIV>”. “<DIV>” is simply a wrapper over the grid which helps to represent the scrollable option.
  3. Now, fix/freeze the “<THEAD>” using a technique applicable to the browser (because different browsers act differently in this case).

Now, whenever you scroll the grid rows, the header always stays on the top row.

Using the Code

The complete sample code is given below. You can also download the sample project from the above link.

ASP.NET
<%@ Page Language="C#" AutoEventWireup="true" 
         CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<style type="text/css">
    .WrapperDiv 
    {
        width:560px;height:290px;border: 1px solid black;
    }        
    .WrapperDiv TH 
    {
        /* Needed for IE */
         position: relative;
    }
    .WrapperDiv TR 
    {
        /* Needed for IE */
        height:0px;
    }
    .ScrollContent 
    {
        /* Needed for Opera */
        display: block;
        overflow: auto;
        width: 100%;
        height: 250px;
    }
    .FixedHeader
    {
        /* Needed for opera */
        display: block;
    }
    
</style>

<script runat="server">
  ICollection CreateDataSource( )
  {
    System.Data.DataTable dt = new System.Data.DataTable();
    System.Data.DataRow dr;
    dt.Columns.Add(new System.Data.DataColumn("Product Id", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("Product Name", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("Product Price", typeof(System.Decimal)));
    dt.Columns.Add(new System.Data.DataColumn("Manufacture Time", typeof(System.String)));
    dt.Columns.Add(new System.Data.DataColumn("Expired Time", typeof(System.String)));
    
    for (int i = 1; i <= 50; i++)
    {
      System.Random rd = new System.Random(Environment.TickCount * i); ;
      dr = dt.NewRow();
      dr[0] = i.ToString();
      dr[1] = "Sample Product" + i.ToString();
      dr[2] = System.Math.Round(rd.NextDouble() * 100, 2);
      dr[3] = "September/2008";
      dr[4] = "September/2012";
      dt.Rows.Add(dr);
    }
    System.Data.DataView dv = new System.Data.DataView(dt);
    return dv;
  }

  protected void Page_Load( object sender, EventArgs e )
  {
    if (!IsPostBack)
    {
      GridView1.DataSource = CreateDataSource();
      GridView1.DataBind();
    }
  }
  
</script>

<script type="text/ecmascript">

    var headerHeight = 8;

    /// <summary>
    ///  Responsible for call appropriate function according to browser
    ///  for Browser Compatibility
    /// </summary>
    function onLoad()
    {
        if(navigator.appName == "Opera")
        {
            freezeGridViewHeaderForOpera('GridView1');
        }
        else
        {
            freezeGridViewHeaderForIEAndFF('GridView1','WrapperDiv');
        }
    }
    
    /// <summary>
    ///  Used to create a fixed GridView header and allow scrolling
    ///  for IE and FF (Tested in IE-7 and FF-3.0.3)
    /// </summary>
    /// <param name="gridViewId" type="String">
    ///   Client-side ID of the GridView control
    /// </param>
    /// <param name="wrapperDivCssClass" type="String">
    ///   CSS class to be applied to the GridView's wrapper div element.
    /// </param>
    function freezeGridViewHeaderForIEAndFF(gridViewId,wrapperDivCssClass) 
    {
        var grid = document.getElementById(gridViewId);
        if (grid != 'undefined')
        {
            grid.style.visibility = 'hidden';
            
            var div = null;
            if (grid.parentNode != 'undefined') 
            {
                //Find wrapper div output by GridView
                div = grid.parentNode;
                if (div.tagName == "DIV")
                {
                    div.className = wrapperDivCssClass;  
                    div.style.overflow = "auto";             
                }
            }  
                       
            var grid = prepareFixedHeader(grid);
            var tbody = grid.getElementsByTagName('TBODY')[0];
            
            //Needed for Firefox
            tbody.style.height = (div.offsetHeight -  headerHeight) + 'px';

            tbody.style.overflowX = "hidden";
            tbody.overflow = 'auto';
            tbody.overflowX = 'hidden';
             
            grid.style.visibility = 'visible';
        }
    }
    
    /// <summary>
    ///  Used to create a fixed GridView header and allow scrolling
    ///  for Opera (Tested in Opera-9.2)
    /// </summary>
    /// <param name="gridViewId" type="String">
    ///   Client-side ID of the GridView control
    /// </param>
    function freezeGridViewHeaderForOpera(gridViewId)
    {
        var grid = document.getElementById(gridViewId);
        if (grid != 'undefined')
        {
            grid = prepareFixedHeader(grid);

            var headers = grid.getElementsByTagName('THEAD')[0];
            headers.className = "FixedHeader";
            
            var tbody = grid.getElementsByTagName('TBODY')[0];
            tbody.className = "ScrollContent";
            var cells = tbody.childNodes[0];

            for(var i = 0; i < cells.childNodes.length;i++)
            {
                var tableCell = cells.childNodes[i];
                var tableCellWidth = getStyle(tableCell,'width')
                var headerCell = headers.childNodes[0].childNodes[i];

                var headerCellWidth = getStyle(headerCell,'width');

                if(widthPxToInt(tableCellWidth) > widthPxToInt(headerCellWidth))
                {
                    headerCell.style.width=(widthPxToInt(tableCellWidth) - 10) + "px";
                }
                else
                {
                    tableCell.style.width=(widthPxToInt(headerCellWidth) - 10) + "px";
                }
            }
        }
    }
    
    /// <summary>
    ///  Used to prepare a fixed GridView header
    /// </summary>
    /// <param name="grid" type="GridView">
    ///   The Reference Of GridView control
    /// </param>
    function prepareFixedHeader(grid)
    {
        //Find DOM TBODY element and  and 
        var tags = grid.getElementsByTagName('TBODY');
        if (tags != 'undefined')
        {
            var tbody = tags[0];
            
            var trs = tbody.getElementsByTagName('TR');

            if (trs != 'undefined') 
            {
                headerHeight += trs[0].offsetHeight;
                
                //Remove first TR tag from it        
                var headTR = tbody.removeChild(trs[0]);
                
                //create a new element called THEAD
                var head = document.createElement('THEAD');
                head.appendChild(headTR);
                
                //add to a THEAD element instead of TR so CSS styles
                //can be applied properly in both IE and FireFox
                grid.insertBefore(head, grid.firstChild);
            }
       }
       
       return grid;
    }
    
    function getStyle(oElm, strCssRule)
    {
        var strValue = "";
        if(document.defaultView && document.defaultView.getComputedStyle){
           strValue = document.defaultView.getComputedStyle(oElm, 
                               "").getPropertyValue(strCssRule);
        }
        else if(oElm.currentStyle){
            strCssRule = strCssRule.replace(/\-(\w)/g, function (strMatch, p1){
                return p1.toUpperCase();
            });
            strValue = oElm.currentStyle[strCssRule];
        }
        return strValue;
    }
    
    /// <summary>
    ///  Used to convert from Pxel to Integer
    /// </summary>
    /// <param name="width" type="String">
    ///  Width of any thing like GridHeader,GridCell
    /// </param>    
    function widthPxToInt(width)
    {
        width = width.substr(0,width.length-2);
        return new Number(width);
    }
    
    
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:GridView ID="GridView1" runat="server" 
              Font-Size="12px" BackColor="#FFFFFF"
              GridLines="Both" CellPadding="4" Width="560px">
          <HeaderStyle BackColor="#EDEDED" Height="26px" />
        </asp:GridView>
    </div>
    </form>
</body>
</html>

<script type="text/ecmascript">   
    window.onload = onLoad();
</script>

Browser Compatibility

Since I have used JavaScript and CSS to solve this problem, there is no doubt that it will raise the question, “Is the solution compatible for all browsers?”. If you Google, you will find lots of solutions for this problem. But, I have not yet found any client-side solution that supports all the browsers. Most of the solutions support Firefox and IE. But, very few support Opera.

I did test my provided solution in FireFox-3.0.3 , IE-7, and Opera-9.2 and got successful results.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior) somewhere in...
Bangladesh Bangladesh
Working in a Nordic company, developing some really interesting solutions for GSM Mobile Service Providers in Bangladesh. I work as a senior software developer there. Developed framework of challenging web based application. Build and manage a complete dynamic accounting and inventory management system which is tag based software. Enjoy learning about latest technology. Main working arenas are asp.net 2.0/3.5.

Comments and Discussions

 
QuestionFreeze header along with horizontal and vertical scroll Pin
Member 149621079-Nov-20 23:36
Member 149621079-Nov-20 23:36 
GeneralMy vote of 5 Pin
Er. Anil Yadav15-Sep-13 21:46
Er. Anil Yadav15-Sep-13 21:46 
QuestionPerformance Pin
SumanRoy23-Dec-12 23:50
SumanRoy23-Dec-12 23:50 
QuestionIE8 / Chrome / Visual Studio 2010 Pin
sgv200019-Jun-12 14:34
sgv200019-Jun-12 14:34 
Generalnot worked in IE8 Pin
Moosdau24-Apr-11 3:45
Moosdau24-Apr-11 3:45 
GeneralRe: not worked in IE8 [modified] Pin
greentea_60029-Jul-11 17:24
greentea_60029-Jul-11 17:24 
Generalchrome related Pin
amit22Dec1021-Dec-10 19:12
amit22Dec1021-Dec-10 19:12 
GeneralScript is not working Pin
cliff clavin4-Jan-10 8:16
cliff clavin4-Jan-10 8:16 
GeneralFreezing header and left columns in table using jquery Pin
manisha67616-Dec-09 5:51
manisha67616-Dec-09 5:51 
Generalusing this code in vb Pin
loxzide30-Sep-09 17:04
loxzide30-Sep-09 17:04 
GeneralFreeze header. freeze footer and freeze left column Pin
sandeepkumars10-Aug-09 1:07
sandeepkumars10-Aug-09 1:07 
Generalworks in ie 6,7 but not 8 Pin
walshy00720-Jul-09 3:52
walshy00720-Jul-09 3:52 
GeneralRe: works in ie 6,7 but not 8 Pin
Member 391887021-Jul-09 9:32
Member 391887021-Jul-09 9:32 
GeneralExample in Visual Basic Pin
Revalk1-Jul-09 9:45
Revalk1-Jul-09 9:45 
General**Horizontal scroll bar** Pin
scorpioyas1-Jul-09 0:32
scorpioyas1-Jul-09 0:32 
Generaltable header in IE overlap the scroll bar Pin
monu nair18-Jun-09 20:33
monu nair18-Jun-09 20:33 
Generalin IE on scroll it show the text behind the header [modified] Pin
monu nair16-Jun-09 21:18
monu nair16-Jun-09 21:18 
Questionhow to remove the horizontal bar Pin
monu nair15-Jun-09 19:47
monu nair15-Jun-09 19:47 
GeneralVery Good - Just need some tweaks for Chrome/Safari Pin
andrew6ger19-May-09 3:52
andrew6ger19-May-09 3:52 
Generalfreeze the header & Column of gridview Pin
nadeem20031-Feb-09 19:43
nadeem20031-Feb-09 19:43 
GeneralProblem when executing with grid view in content pages Pin
Qot15-Jan-09 20:03
Qot15-Jan-09 20:03 
GeneralRe: Problem when executing with grid view in content pages Pin
DrShrinker22-Apr-09 8:27
DrShrinker22-Apr-09 8:27 
QuestionWhat about sorting? Pin
eashwar v19-Dec-08 18:44
eashwar v19-Dec-08 18:44 
GeneralCouple of problems I noticed after building the sample... Pin
Justin Freitas1-Nov-08 3:32
Justin Freitas1-Nov-08 3:32 
GeneralRe: Couple of problems I noticed after building the sample... [modified] Pin
Razwan Kader1-Nov-08 18:51
Razwan Kader1-Nov-08 18:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.