KendoReact Data Grid (Table) Overview

The KendoReact Data Grid (Table) provides 100+ ready-to-use features covering everything from paging, sorting, filtering,editing, and grouping to row and column virtualization, export to PDF and Excel and accessibility.

The KendoReact Grid is built on React from the ground up, with zero dependencies, by developers with 10+ years of experience in making enterprise-ready Grids. This results in a React data grid that delivers lighting fast performance and is highly customizable.

Features Preview and Demo

Among the many features which the KendoReact Data Grid delivers are:

  • Paging—You also have the option to add a pager for easier navigation.
  • Sorting—Apart from the sorting and unsorting options of multiple columns, you can also pre-sort the data records of the Grid.
  • Filtering—Including additional cell customization options.
  • Grouping—Out of the box, you can apply dynamic grouping to the data Grid records, set grouping by aggregate values, and similar to the sorting functionality pre-group the data.
  • Editing—Depending on your users' requirements, you can opt for the inline or the in-cell edit modes, provide editing from an external form or Redux Form, and also further customize the Grid.
  • Row selection—You can additionally configure it by enabling or disabling the checkbox and row selection options.
  • Export to PDF and Excel—When implementing the Grid export to PDF, you can set the fonts, the exact portion and layout of the exported content, also customize the columns and other specifics of the output result. When exporting to Excel, you can export specific data and customize the exported columns.
  • Custom renderer—Based on a value, you can also use conditional formatting (highlight a data table cell).
  • Locked columns—When your Grid has to display large amounts of data, the frozen columns feature enables you to lock any of the Grid columns by just setting the locked column property.
  • Virtualization—The Grid supports virtualization of both column and row data. This feature boosts the performance of the component when displaying large data tables as it dynamically renders only a portion of the rows and the columns.
  • Column reordering—Reordering can be enabled for any column and is seamlessly integrated with the available Grid features, including locked columns.
  • Column resizing—Resizing takes place real-time but can also be controlled from the outside.
  • Detail templates—The detail rows of the Grid provide additional details about a particular row of table data through expanding or collapsing its content.
  • Globalization—By using the available globalization options in KendoReact, you can translate the Grid messages by adapting them to specific culture locales.
import React from 'react';
import ReactDOM from 'react-dom';
import { Grid, GridColumn, GridDetailRow, GridToolbar } from '@progress/kendo-react-grid';
import { DropDownList } from '@progress/kendo-react-dropdowns';
import { GridPDFExport } from '@progress/kendo-react-pdf';
import { ExcelExport } from '@progress/kendo-react-excel-export';
import { IntlProvider, load, LocalizationProvider, loadMessages } from '@progress/kendo-react-intl';

import likelySubtags from 'cldr-core/supplemental/likelySubtags.json';
import currencyData from 'cldr-core/supplemental/currencyData.json';
import weekData from 'cldr-core/supplemental/weekData.json';

import numbers from 'cldr-numbers-full/main/es/numbers.json';
import currencies from 'cldr-numbers-full/main/es/currencies.json';
import caGregorian from 'cldr-dates-full/main/es/ca-gregorian.json';
import dateFields from 'cldr-dates-full/main/es/dateFields.json';
import timeZoneNames from 'cldr-dates-full/main/es/timeZoneNames.json';

load(
    likelySubtags,
    currencyData,
    weekData,
    numbers,
    currencies,
    caGregorian,
    dateFields,
    timeZoneNames
);

import esMessages from './es.json';
loadMessages(esMessages, 'es-ES');

import { process } from '@progress/kendo-data-query';
import orders from './orders.json';

orders.forEach(o => {
    o.orderDate = new Date(o.orderDate);
    o.shippedDate = o.shippedDate === 'NULL' ? undefined : new Date(o.shippedDate);
});

class DetailComponent extends GridDetailRow {
    render() {
        const dataItem = this.props.dataItem;
        return (
            <div>
                <section style={{ width: "200px", float: "left" }}>
                    <p><strong>Street:</strong> {dataItem.shipAddress.street}</p>
                    <p><strong>City:</strong> {dataItem.shipAddress.city}</p>
                    <p><strong>Country:</strong> {dataItem.shipAddress.country}</p>
                    <p><strong>Postal Code:</strong> {dataItem.shipAddress.postalCode}</p>
                </section>
                <Grid style={{ width: "500px" }} data={dataItem.details}></Grid>
            </div>
        );
    }
}

class App extends React.Component {
    locales = [
        {
            language: 'en-US',
            locale: 'en'
        },
        {
            language: 'es-ES',
            locale: 'es'
        }
    ]
    constructor(props) {
        super(props);
        const dataState = {
            skip: 0,
            take: 20,
            sort: [
                { field: 'orderDate', dir: 'desc' }
            ],
            group: [
                { field: 'customerID' }
            ]
        };
        this.state = {
            dataResult: process(orders, dataState),
            dataState: dataState,
            currentLocale: this.locales[0]
        };
    }

    dataStateChange = (event) => {
        this.setState({
            dataResult: process(orders, event.data),
            dataState: event.data
        });
    }

    expandChange = (event) => {
        const isExpanded =
            event.dataItem.expanded === undefined ?
                event.dataItem.aggregates : event.dataItem.expanded;
        event.dataItem.expanded = !isExpanded;

        this.setState({ ...this.state });
    }

    _pdfExport;
    exportExcel = () => {
        this._export.save();
    }

    _export;
    exportPDF = () => {
        this._pdfExport.save();
    }

    render() {
        return (
            <LocalizationProvider language={this.state.currentLocale.language}>
                <IntlProvider locale={this.state.currentLocale.locale} >
                    <div>
                        <ExcelExport
                            data={orders}
                            ref={(exporter) => { this._export = exporter; }}
                        >
                            <Grid
                                style={{ height: '700px' }}
                                sortable
                                filterable
                                groupable
                                reorderable
                                pageable={{ buttonCount: 4, pageSizes: true }}

                                data={this.state.dataResult}
                                {...this.state.dataState}
                                onDataStateChange={this.dataStateChange}

                                detail={DetailComponent}
                                expandField="expanded"
                                onExpandChange={this.expandChange}
                            >
                                <GridToolbar>
                                    Locale:&nbsp;&nbsp;&nbsp;
                                    <DropDownList
                                        value={this.state.currentLocale}
                                        textField="language"
                                        onChange={(e) => { this.setState({ currentLocale: e.target.value }); }}
                                        data={this.locales} />&nbsp;&nbsp;&nbsp;
                                    <button
                                        title="Export to Excel"
                                        className="k-button k-primary"
                                        onClick={this.exportExcel}
                                    >
                                        Export to Excel
                                    </button>&nbsp;
                                    <button className="k-button k-primary" onClick={this.exportPDF}>Export to PDF</button>
                                </GridToolbar>
                                <GridColumn field="customerID" width="200px" />
                                <GridColumn field="orderDate" filter="date" format="{0:D}" width="300px" />
                                <GridColumn field="shipName" width="280px" />
                                <GridColumn field="freight" filter="numeric" width="200px" />
                                <GridColumn field="shippedDate" filter="date" format="{0:D}" width="300px" />
                                <GridColumn field="employeeID" filter="numeric" width="200px" />
                                <GridColumn locked field="orderID" filterable={false} title="ID" width="90px" />
                            </Grid>
                        </ExcelExport>
                        <GridPDFExport
                            ref={(element) => { this._pdfExport = element; }}
                            margin="1cm" >
                            {<Grid data={process(orders, { skip: this.state.dataState.skip, take: this.state.dataState.take })} >
                                <GridColumn field="customerID" width="200px" />
                                <GridColumn field="orderDate" filter="date" format="{0:D}" width="300px" />
                                <GridColumn field="shipName" width="280px" />
                                <GridColumn field="freight" filter="numeric" width="200px" />
                                <GridColumn field="shippedDate" filter="date" format="{0:D}" width="300px" />
                                <GridColumn field="employeeID" filter="numeric" width="200px" />
                                <GridColumn locked field="orderID" filterable={false} title="ID" width="90px" />
                            </Grid>}
                        </GridPDFExport>
                    </div>
                </IntlProvider>
            </LocalizationProvider>
        );
    }
}

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