New to Telerik UI for Blazor? Download free 30-day trial

Multi-Column Headers

The Treelist allows you to stack several columns under one header to visually group relevant fields for your end users.

To use multiple column headers:

  1. Define a TreeListColumn instance for each multi-column header you want. Set its Title or HeaderTemplate.
  2. Under its <Columns> nested tag, add the columns you want it to contain.

While you can set all the parameters of such a multi-column header column, it only supports and works with the Title, and the nested HeaderTemplate and Columns tags (templates).

You will find the following sections in this article:

Basic Example

The following code snippet shows how you can group columns in the Treelist in multi-column headers. You can also use "regular" columns at the root level, not all of them have to be column groups.

Multiple Column Headers in the Treelist

multi-column headers example

@* See the root-level TreeListColumn tags that have their own Columns collections *@

<TelerikTreeList Data=@TreeListData
                 Pageable="true" Sortable="true" Resizable="true" Reorderable="true"
                 FilterMode="@TreeListFilterMode.FilterMenu"
                 Width="900px" Height="400px"
                 IdField="Id" ParentIdField="ParentId">
    <TreeListColumns>
        <TreeListColumn Title="Personal Information" Reorderable="false">
            <Columns>
                <TreeListColumn Expandable="true" Field=@nameof(Customer.FirstName) Title="First Name" Width="115px" />
                <TreeListColumn Field=@nameof(Customer.LastName) Title="Last Name" Width="105px" />
            </Columns>
        </TreeListColumn>
        <TreeListColumn Title="Company">
            <Columns>
                <TreeListColumn Field=@nameof(Customer.CompanyName) Title="Name" />
                <TreeListColumn Field=@nameof(Customer.HasCompanyContract) Title="Has Contract" Width="115px" />
            </Columns>
        </TreeListColumn>
        <TreeListColumn Title="Contact Details">
            <Columns>
                <TreeListColumn Field="@nameof(Customer.Email)" Title="Email"></TreeListColumn>
                <TreeListColumn Field="@nameof(Customer.Phone)" Title="Phone" Width="120px"></TreeListColumn>
                <TreeListColumn Field="@nameof(Customer.City)" Title="City" Width="100px"></TreeListColumn>
            </Columns>
        </TreeListColumn>
        <TreeListColumn Title="Admin Settings">
            <Columns>
                <TreeListColumn Field=@nameof(Customer.Id) Title="UserID" />
                <TreeListColumn Field=@nameof(Customer.PasswordHash) Title="Pass Hash" Width="100px" />
            </Columns>
        </TreeListColumn>
    </TreeListColumns>
</TelerikTreeList>

@code {
    public List<Customer> TreeListData { get; set; }

    public class Customer
    {
        public int Id { get; set; }
        public int? ParentId { get; set; }
        public string PasswordHash { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string CompanyName { get; set; }
        public bool HasCompanyContract { get; set; }
        public string Email { get; set; }
        public string Phone { get; set; }
        public string City { get; set; }
    }

    // generation of dummy data
    protected override void OnInitialized()
    {
        TreeListData = GenerateData();
    }

    List<Customer> GenerateData()
    {
        var data = new List<Customer>();

        string[] fNames = new string[] { "Nancy", "John", "Orlando", "Jane", "Bob", "Juan" };
        string[] lNames = new string[] { "Harris", "Gates", "Smith", "Caprio", "Gash", "Gee" };
        string[] cNames = new string[] { "Acme", "Northwind", "Contoso" };
        string[] cities = new string[] { "Denver", "New York", "LA", "London", "Paris", "Helsinki", "Moscow", "Sofia" };
        Random rnd = new Random();

        for (int i = 0; i < 150; i++)
        {
            string fName = fNames[rnd.Next(0, fNames.Length)];
            string lName = lNames[rnd.Next(0, lNames.Length)];
            string cName = cNames[rnd.Next(0, cNames.Length)];
            data.Add(new Customer
            {
                Id = i,
                ParentId = GetParentId(i),
                PasswordHash = "not shown",
                FirstName = fName,
                LastName = lName,
                CompanyName = cName,
                HasCompanyContract = i % 3 == 0,
                Email = $"{fName}.{lName}@{cName}.com".ToLowerInvariant(),
                Phone = $"{rnd.Next(100, 999)}-555-{rnd.Next(100, 999)}",
                City = cities[rnd.Next(0, cities.Length)]
            });
        }

        return data;
    }

    int? GetParentId(int index)
    {
        if (index % 4 == 0) return null;
        return Math.Abs(index - (index % 4));
    }
}

Behavior With Other Features

This section explains how using multi column headers changes behaviors of other component functionalities or how certain features behave with multi-column headers. If a feature is not listed, it is not affected.

Width

The Width paramter of a multi-column header is ignored, its width depends on the sum of the widths for its child columns.

Sorting, Filtering, Grouping, Editing

These functionalities do not work on a multi-column header column, but only on the actual child columns.

The column used for the multiple column header serves for presentation purposes only. It does not use the Field parameter and cannot perform data source operations such as filtering, sorting, grouping, editing, because they would span several fields and that is not possible.

Individual columns under a shared group header can be sorted, filtered, grouped and edited as usual.

Resizing

Multi-column headers can be resized and resizing is similar to standard columns.

Individual columns under a shared group header can be resized as well.

The Resizable parameter is honored for both individual columns and column group headers.

Reordering

Column reordering works according to the following rules:

  • Root multi-header columns can be reordered with other root multi-header columns.
    • Reordering a group of columns moves all its child columns as well.
  • Individual columns can be reordered within their parent group only.
    • Child columns of different parent columns (and/or on different levels) cannot be reordered.

The Reordable parameter is honored for both individual columns and column group headers.

Column Menu

A multi-header column does not show up in the list of columns in the column chooser of individual columns from the last level. If you hide all child columns, the parent column will also hide.

State Management

The state of a multi-header column is handled in the same way as a standard column. The columns in the state are listed in a flat list in the order of definition. For example, for the following setup:

<TelerikGrid>
    <GridColumns>
        <GridColumn Title="column 1">
            <Columns>
                <GridColumn Title="column 1.1" />
                <GridColumn Title="column 1.2" />
            </Columns>
        </GridColumn>

        <GridColumn Title="column 2"></GridColumn>
    </GridColumns>
</TelerikGrid>

The State will be:

Column state index Column
0 column 1
1 column 1.1
2 column 1.2
3 column 2

Note that this order is different than the order in which the blazor framework initializes the column components, its goal is to be similar to a human-readable order that matches the column definition.

Locked columns

You can lock an entire multi-column header through its Locked parameter. Doing so will lock all its child columns.

Therefore, we advise that you do not set Locked=false for child columns of locked parent columns, and you can consider setting Lockable=false on them to prevent the user from unpinning them and getting sub-optimal layout. Setting Locked=true for a child column is not supported.

Keyboard navigation

The keyboard navigation in the multi-column headers follows the functionality of Excel.

See Also

In this article