Column Menu

The KendoReact Data Grid 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.

Basic Usage

To configure the column menu, use the columnMenu option of the columns.

The following example demonstrates how to utilize the components for sorting and filtering while you implement the column menu in the Grid.

import React from 'react';
import ReactDOM from 'react-dom';
import { process } from '@progress/kendo-data-query';
import {
    Grid, GridColumn as Column
} from '@progress/kendo-react-grid';

import { ColumnMenu } from './columnMenu.jsx';

import products from './products.json';

class App extends React.Component {
    constructor(props) {
        super(props);

        this.state = this.createDataState({
            take: 8,
            skip: 0
        });
    }

    createDataState(dataState) {
        return {
            result: process(products.slice(0), dataState),
            dataState: dataState
        };
    }

    dataStateChange = (event) => {
        this.setState(this.createDataState(event.data));
    }

    render() {
        return (
            <div>
                <Grid
                    data={this.state.result}
                    {...this.state.dataState}
                    onDataStateChange={this.dataStateChange}
                    sortable={true}
                    pageable={true}
                    pageSize={8}
                >
                    <Column field="ProductID" title="Product Id" filter={'numeric'} columnMenu={ColumnMenu}/>
                    <Column field="ProductName" columnMenu={ColumnMenu}/>
                    <Column field="UnitPrice" filter={'numeric'} columnMenu={ColumnMenu} />
                    <Column field="Discontinued" filter={'boolean'} columnMenu={ColumnMenu} />
                </Grid>
                <br />
            </div>
        );
    }
}

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

Custom Components

You can integrate custom components in the column menu and pass additional properties to them.

The following example demonstrates how to:

  • Render the columns inside the column menu based on an array of the column names and on the column show property.
  • Hide columns from the column menu and enable the Grid to update the column menu accordingly.

To access all demo files, refer to the tree pane of the file.

import React from 'react';
import ReactDOM from 'react-dom';
import { process } from '@progress/kendo-data-query';
import {
    Grid, GridColumn as Column
} from '@progress/kendo-react-grid';

import { CustomColumnMenu } from './customColumnMenu.jsx';

import products from './products.json';
import columns from './columns.js';

class App extends React.Component {
    constructor(props) {
        super(props);

        const dataState = this.createDataState({
            take: 8,
            skip: 0
        });

        this.state = {
            columns: columns,
            ...dataState
        };
    }

    createDataState(dataState) {
        return {
            result: process(products.slice(0), dataState),
            dataState: dataState
        };
    }

    dataStateChange = (event) => {
        this.setState(this.createDataState(event.data));
    }

    onColumnsSubmit = (columnsState) => {
        this.setState({
            columns: columnsState
        });
    }

    render() {
        return (
            <div>
                <Grid
                    data={this.state.result}
                    {...this.state.dataState}
                    onDataStateChange={this.dataStateChange}
                    sortable={true}
                    pageable={true}
                    pageSize={8}
                >
                    {
                        this.state.columns.map((column, idx) =>
                            column.show && (<Column
                                key={idx}
                                field={column.field}
                                title={column.title}
                                filter={column.filter}
                                columnMenu={
                                    props =>
                                        <CustomColumnMenu
                                            {...props}
                                            columns={this.state.columns}
                                            onColumnsSubmit={this.onColumnsSubmit}
                                        />
                                }
                            />)
                        )}
                </Grid>
                <br />
            </div>
        );
    }
}

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

Customizing the Filter Component

The filter component of the column menu enables you to customize its user interface (UI) by passing a custom component to the filterUI property.

The following example demonstrates how to customize the UI of the column-menu filter component. To access all demo files, refer to the tree pane of the file.

import React from 'react';
import ReactDOM from 'react-dom';
import { process } from '@progress/kendo-data-query';
import {
    Grid, GridColumn as Column
} from '@progress/kendo-react-grid';

import { CustomFilterUI } from './customFilterUI.jsx';
import {
    GridColumnMenuFilter
} from '@progress/kendo-react-grid';

import products from './products.json';

class App extends React.Component {
    constructor(props) {
        super(props);

        const dataState = this.createDataState({
            take: 8,
            skip: 0
        });

        this.state = {
            ...dataState
        };
    }

    createDataState(dataState) {
        return {
            result: process(products.slice(0), dataState),
            dataState: dataState
        };
    }

    dataStateChange = (event) => {
        this.setState(this.createDataState(event.data));
    }

    render() {
        return (
            <div>
                <Grid
                    data={this.state.result}
                    {...this.state.dataState}
                    onDataStateChange={this.dataStateChange}
                    sortable={true}
                    pageable={true}
                    pageSize={8}
                >
                    <Column field={'ProductName'} title={'Product Name'} />
                    <Column
                        field={'Discontinued'}
                        title={'Discontinued'}
                        filter={'boolean'}
                        columnMenu={
                            props =>
                                <GridColumnMenuFilter
                                    {...props}
                                    filterUI={CustomFilterUI}
                                />
                        }
                    />
                </Grid>
                <br />
            </div>
        );
    }
}

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

Styling the Column Menu Icon

Both the GridColumnMenuFilter and GridColumnMenuSort components expose the active static method which checks if filtering and sorting are applied to a specific field. You can use these methods for applying custom CSS classes to the column menu and mark it as active.

The following example demonstrates how to style the column-menu icon when sorting and filtering are applied.

<style>
    th.k-header.active > div > div {
        color: #fff;
        background-color: #ff6358;
    }
</style>
const products = [{
    "ProductID" : 1,
    "ProductName" : "Chai",
    "UnitPrice" : 18.0000,
    "Discontinued" : false
}];

class ColumnMenu extends React.Component {
    render() {
        return (
        <div>
            <GridColumnMenuSort {...this.props} />
            <GridColumnMenuFilter {...this.props} />
        </div>);
    }
}

class App extends React.Component {
    constructor(props) {
        super(props);

        this.state = this.createDataState({
            take: 8,
            skip: 0
        });
    }

    createDataState(dataState) {
        return {
            result: process(products.slice(0), dataState),
            dataState: dataState
        };
    }

    dataStateChange = (event) => {
        this.setState(this.createDataState(event.data));
    }

    columnProps(field) {
        return {
            field: field,
            columnMenu: ColumnMenu,
            headerClassName: this.isColumnActive(field, this.state.dataState) ? 'active' : ''
        };
    }

    isColumnActive(field, dataState) {
        return GridColumnMenuFilter.active(field, dataState.filter) ||
                GridColumnMenuSort.active(field, dataState.sort);
    }

    render() {
        return (<Grid
            data={this.state.result}
            {...this.state.dataState}
            onDataStateChange={this.dataStateChange}
            sortable={true}
            pageable={true}
            pageSize={8}
        >
            <GridColumn {...this.columnProps('ProductID')} filter={'numeric'} />
            <GridColumn {...this.columnProps('ProductName')} />
            <GridColumn {...this.columnProps('UnitPrice')} filter={'numeric'} />
            <GridColumn {...this.columnProps('Discontinued')} filter={'boolean'} />
        </Grid>
        );
    }
}

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