Column Menu

The KendoReact TreeList enables you to show a menu with quick actions for its columns.

The column menu provides flexible options for high-level customization. For example, the regular sorting and filtering features are represented by individual components which allows you to implement complex scenarios and meet the specific requirements of your project.

The TreeList component is part of KendoReact, a professionally built commercial UI library. To try out this component you need to sign up for a 30-day trial, which gives you access to the full KendoReact library.

Basic Usage

To configure the column menu, use the columnMenu option of the columns and pass the corresponding ColumnMenu component base on the column data type.

import React from 'react';
import ReactDOM from 'react-dom';
import {
    TreeList, filterBy, orderBy, extendDataItem, mapTree
} from '@progress/kendo-react-treelist';

import {
    ColumnMenuTextColumn, ColumnMenuNumericColumn,
    ColumnMenuDateColumn, ColumnMenuBooleanColumn
} from '@progress/kendo-react-data-tools';

import employees from './data';

const subItemsField = 'employees';
const expandField = 'expanded';
const columns = [
    { field: 'name', title: 'Name', width: 320, columnMenu: ColumnMenuTextColumn, expandable: true },
    { field: 'hireDate', title: 'Hire Date', width: 280, format: '{0:d}', columnMenu: ColumnMenuDateColumn },
    { field: 'timeInPosition', title: 'Year(s) in Position', width: 280, columnMenu: ColumnMenuNumericColumn },
    { field: 'fullTime', title: 'Full Time', width: 190, columnMenu: ColumnMenuBooleanColumn }
];

class App extends React.Component {
    state = {
        data: [ ...employees ],
        filter: [],
        sort: [],
        expanded: [1, 2, 32]
    }

    onExpandChange = (e) => {
        this.setState({
            expanded: e.value ?
                this.state.expanded.filter(id => id !== e.dataItem.id) :
                [ ...this.state.expanded, e.dataItem.id ]
        });
    }

    onSortChange = (event) => {
        this.setState({
            sort: event.sort
        });
    }

    handleFilterChange = (event) => {
        this.setState({
            filter: event.filter
        })
    }

    addExpandField = (dataTree) => {
        const expanded = this.state.expanded;
        return mapTree(dataTree, subItemsField, (item) =>
            extendDataItem(item, subItemsField, {
                [expandField]: expanded.includes(item.id)
            })
        );
    }

    processData = () => {
        const { data, filter, sort } = this.state;

        const dataTree = orderBy(filterBy(data, filter, subItemsField), sort, subItemsField);
        return this.addExpandField(dataTree);
    }

    render() {
        return (
            <TreeList
                style={{ maxHeight: '590px', overflow: 'auto' }}
                expandField={expandField}
                subItemsField={subItemsField}
                onExpandChange={this.onExpandChange}
                data={this.processData()}
                columns={columns}

                columnMenuFilter={this.state.filter}
                onColumnMenuFilterChange={this.handleFilterChange}
                onSortChange={this.onSortChange}
                sort={this.state.sort}
            />
        );
    }
}

ReactDOM.render(
    <App />,
    document.querySelector('my-app')
);

Customizing the Column Menu

The built-in Column Menu components can be customized using their props, which includes show and hide of the sort buttons, and customizing filtering components.

The following example demonstrates how to customize the column menus:

  • Text ColumnMenu
    • change filter operators
    • disable the logic DropDownList
    • change the initial filter, which changes the default values of the filter components
  • Numeric ColumnMenu
    • setting a single filter in the filterContent prop
    • change the initialFilter, which is required since we use a single filter
  • Date ColumnMenu
    • remove sorting
  • Boolean ColumnMenu
    • implement a custom filter editor
import React from 'react';
import ReactDOM from 'react-dom';
import {
    TreeList, filterBy, orderBy, extendDataItem, mapTree
} from '@progress/kendo-react-treelist';

import { ColumnMenuCustomTextColumn } from './textColumnMenu.jsx'
import { ColumnMenuCustomNumericColumn } from './numericColumnMenu.jsx';
import { ColumnMenuCustomDateColumn } from './dateColumnMenu.jsx';
import { ColumnMenuCustomBooleanColumn } from './booleanColumnMenu.jsx';

import employees from './data';

const subItemsField = 'employees';
const expandField = 'expanded';

const columns = [
    { field: 'name', title: 'Name', width: 320, expandable: true, columnMenu: ColumnMenuCustomTextColumn },
    { field: 'hireDate', title: 'Hire Date', width: 280, format: '{0:d}', columnMenu: ColumnMenuCustomDateColumn },
    { field: 'timeInPosition', title: 'Year(s) in Position', width: 280, columnMenu: ColumnMenuCustomNumericColumn },
    { field: 'fullTime', title: 'Full Time', width: 190, columnMenu: ColumnMenuCustomBooleanColumn }
];

class App extends React.Component {
    state = {
        data: [ ...employees ],
        filter: [],
        sort: [],
        expanded: [1, 2, 32]
    }

    onExpandChange = (e) => {
        this.setState({
            expanded: e.value ?
                this.state.expanded.filter(id => id !== e.dataItem.id) :
                [ ...this.state.expanded, e.dataItem.id ]
        });
    }

    onSortChange = (event) => {
        this.setState({
            sort: event.sort
        });
    }

    handleFilterChange = (event) => {
        this.setState({
            filter: event.filter
        })
    }

    addExpandField = (dataTree) => {
        const expanded = this.state.expanded;
        return mapTree(dataTree, subItemsField, (item) =>
            extendDataItem(item, subItemsField, {
                [expandField]: expanded.includes(item.id)
            })
        );
    }

    processData = () => {
        const { data, filter, sort } = this.state;

        const dataTree = orderBy(filterBy(data, filter, subItemsField), sort, subItemsField);
        return this.addExpandField(dataTree);
    }

    render() {
        return (
            <TreeList
                style={{ maxHeight: '590px', overflow: 'auto' }}
                expandField={expandField}
                subItemsField={subItemsField}
                onExpandChange={this.onExpandChange}
                data={this.processData()}
                columns={columns}

                columnMenuFilter={this.state.filter}
                onColumnMenuFilterChange={this.handleFilterChange}
                onSortChange={this.onSortChange}
                sort={this.state.sort}
            />
        );
    }
}

ReactDOM.render(
    <App />,
    document.querySelector('my-app')
);