React DataGrid - Implement a Hierarchical Header Filter

DataGrid supports hierarchical data structures in column headerFilters. This tutorial demonstrates how to implement a hierarchical header filter for a specific column.

DevExtreme DataGrid Hierarchical Header Filter

Configure the Header Filter

To configure a hierarchical header filter, specify the following properties:

  • groupInterval
    Assign a string array that contains multiple items to the groupInterval property. Specify the nesting levels you want to implement in this array:

    jQuery
    index.js
    $('#gridContainer').dxDataGrid({
        columns: [{
            headerFilter: {
                groupInterval: ["State", "City"],
            }
        }]
    })
    Angular
    app.component.html
    app.component.ts
    <dx-data-grid ... >
        <dxi-column>
            <dxo-header-filter
                [groupInterval]="groupInterval"
            ></dxo-header-filter>
        </dxi-column>
    </dx-data-grid>
    export class AppComponent {
        groupInterval = ["State", "City"];
    }
    Vue
    App.vue
    <template>
        <DxDataGrid ... >
            <DxColumn ... >
                <DxHeaderFilter
                    :group-interval="groupInterval"
                />
            </DxColumn>
        </DxDataGrid>
    <template>
    
    <script setup lang="ts">
    import { DxDataGrid, DxColumn, DxHeaderFilter } from 'devextreme-vue/data-grid';
    
    const groupInterval = ["State", "City"];
    </script>
    React
    App.tsx
    import { DataGrid, Column, HeaderFilter } from 'devextreme-react/data-grid';
    
    const groupInterval = ["State", "City"];
    
    function App() {
        return (
            <DataGrid ... >
                <Column ... >
                    <HeaderFilter
                        groupInterval={groupInterval}
                    />
                </Column>
            </DataGrid>
        )
    }
  • headerFilter.dataSource
    Configure a hierarchical headerFilter.dataSource following the "tree" DataStructure. Specify the text, value, and items[] properties:

    jQuery
    index.js
    $('#gridContainer').dxDataGrid({
        columns: [{
            headerFilter: {
                groupInterval: ["State", "City"],
                dataSource: [{
                    text: "Arkansas",
                    value: "Arkansas",
                    items: [{
                        text: "Bentonville",
                        value: "Bentonville",
                    }]
                }]
            }
        }]
    })
    Angular
    app.component.html
    app.component.ts
    <dx-data-grid ... >
        <dxi-column>
            <dxo-header-filter
                [groupInterval]="groupInterval"
                [dataSource]="headerFilterDataSource"
            ></dxo-header-filter>
        </dxi-column>
    </dx-data-grid>
    export class AppComponent {
        groupInterval = ["State", "City"];
        headerFilterDataSource = [{
            text: "Arkansas",
            value: "Arkansas",
            items: [{
                text: "Bentonville",
                value: "Bentonville",
            }]
        }];
    }
    Vue
    App.vue
    <template>
        <DxDataGrid ... >
            <DxColumn ... >
                <DxHeaderFilter
                    :group-interval="groupInterval"
                    :data-source="headerFilterDataSource"
                />
            </DxColumn>
        </DxDataGrid>
    <template>
    
    <script setup lang="ts">
    import { DxDataGrid, DxColumn, DxHeaderFilter } from 'devextreme-vue/data-grid';
    
    const groupInterval = ["State", "City"];
    const headerFilterDataSource = [{
        text: "Arkansas",
        value: "Arkansas",
        items: [{
            text: "Bentonville",
            value: "Bentonville",
        }]
    }];
    </script>
    React
    App.tsx
    import { DataGrid, Column, HeaderFilter } from 'devextreme-react/data-grid';
    
    const groupInterval = ["State", "City"];
    const headerFilterDataSource = [{
        text: "Arkansas",
        value: "Arkansas",
        items: [{
            text: "Bentonville",
            value: "Bentonville",
        }]
    }]
    
    function App() {
        return (
            <DataGrid ... >
                <Column ... >
                    <HeaderFilter
                        groupInterval={groupInterval}
                        dataSource={headerFilterDataSource}
                    />
                </Column>
            </DataGrid>
        )
    }

For more information about hierarchical data structures in DevExtreme, refer to the following topic: TreeList - dataStructure.

Update Component Data

To enable selection of all items within a group, add group fields to your data source. For instance, to group an array of cities by state, add a "State" field to each array item:

jQuery
data.js
const cities = [{
    ID: 1,
    City: 'Bentonville',
    State: 'Arkansas',
}, {
    ID: 2,
    City: 'Atlanta',
    State: 'Georgia',
}, {
    // ...
}]
Angular
data.ts
cities = [{
    ID: 1,
    City: 'Bentonville',
    State: 'Arkansas',
}, {
    ID: 2,
    City: 'Atlanta',
    State: 'Georgia',
}, {
    // ...
}]
Vue
data.ts
const cities = [{
    ID: 1,
    City: 'Bentonville',
    State: 'Arkansas',
}, {
    ID: 2,
    City: 'Atlanta',
    State: 'Georgia',
}, {
    // ...
}]
React
data.ts
const cities = [{
    ID: 1,
    City: 'Bentonville',
    State: 'Arkansas',
}, {
    ID: 2,
    City: 'Atlanta',
    State: 'Georgia',
}, {
    // ...
}]

Implement calculateFilterExpression()

To apply hierarchical header filter values, define the calculateFilterExpression function. Return a group filter expression that compares filterValue with both item and group fields:

jQuery
index.js
$('#gridContainer').dxDataGrid({
    columns: [{
        calculateFilterExpression(filterValue, selectedFilterOperation, target) {
            if (target === "headerFilter" && filterValue) {
                return [["City", selectedFilterOperation, filterValue], "or", ["State", selectedFilterOperation, filterValue]];
            }
            return this.defaultCalculateFilterExpression(filterValue, selectedFilterOperations, target);
        },
    }]
})
Angular
app.component.html
app.component.ts
<dx-data-grid ... >
    <dxi-column>
        <dxo-header-filter
            [calculateFilterExpression]="calculateFilterExpression"
        ></dxo-header-filter>
    </dxi-column>
</dx-data-grid>
export class AppComponent {
    calculateFilterExpression(this: DxDataGridTypes.Column, filterValue, selectedFilterOperation, target) {
        if (target === "headerFilter" && filterValue) {
            return [["City", selectedFilterOperation, filterValue], "or", ["State", selectedFilterOperation, filterValue]];
        }
        return this.defaultCalculateFilterExpression(filterValue, selectedFilterOperations, target);
    }
}
Vue
App.vue
<template>
    <DxDataGrid ... >
        <DxColumn ... >
            <DxHeaderFilter
                :group-interval="groupInterval"
                :calculate-filter-expression="calculateFilterExpression"
            />
        </DxColumn>
    </DxDataGrid>
<template>

<script setup lang="ts">
import { DxDataGrid, DxColumn, DxHeaderFilter, type DxDataGridTypes } from 'devextreme-vue/data-grid';

const groupInterval: string[] = ["State", "City"];
function calculateFilterExpression(this: DxDataGridTypes.Column, filterValue, selectedFilterOperation, target) {
    if (target === "headerFilter" && filterValue) {
        return [["City", selectedFilterOperation, filterValue], "or", ["State", selectedFilterOperation, filterValue]];
    }
    return this.defaultCalculateFilterExpression(filterValue, selectedFilterOperations, target);
}
</script>
React
App.tsx
import { DataGrid, Column, HeaderFilter, type DxDataGridTypes } from 'devextreme-react/data-grid';

const groupInterval: string[] = ["State", "City"];

function calculateFilterExpression(this: DxDataGridTypes.Column, filterValue, selectedFilterOperation, target) {
    if (target === "headerFilter" && filterValue) {
        return [["City", selectedFilterOperation, filterValue], "or", ["State", selectedFilterOperation, filterValue]];
    }
    return this.defaultCalculateFilterExpression(filterValue, selectedFilterOperations, target);
}

function App() {
    return (
        <DataGrid ... >
            <Column ... >
                <HeaderFilter
                    groupInterval={groupInterval}
                    calculateFilterExpression={calculateFilterExpression}
                />
            </Column>
        </DataGrid>
    )
}