React DataGrid - Getting Started

DevExtreme includes multiple data management components. You can use them to display tabular, hierarchical, multidimensional data, or present information as cards. For more information about these components and their features, see How to Choose a Data Management Component.

jQuery
NOTE
Before you start the tutorial, ensure DevExtreme is installed in your application.
Angular
NOTE
Before you start the tutorial, ensure DevExtreme is installed in your application.
Vue
NOTE
Before you start the tutorial, ensure DevExtreme is installed in your application.
React
NOTE
Before you start the tutorial, ensure DevExtreme is installed in your application.

The DataGrid component displays data from a local or remote store and allows users to sort, group, filter, and perform other operations on columns and records.

NOTE

Need to create printable documents simply? Try our .NET-based DevExpress Reports: they ship with an intuitive Visual Studio Report Designer, Web Report Designer for end-user ad-hoc reporting, and a rich set of report controls, including cross tabs and charts.

You can generate a variety of report types — from simple mail-merge, table, and vertical reports to master-detail (hierarchical) and cross-tab reports, print or export them to PDF, Excel, and other formats.

Develop using VS Code? Leverage the capabilities of a brand new VS Code Report Designer extension to create and edit reports/documents on any platform, be it Windows, macOS, or Linux.

Get Started with DevExpress Reports | Explore Demos

Use our DevExpress BI Dashboard to embed interactive business intelligence into your next web app.

The Web Dashboard is a data analysis UI component that you can embed into your ASP.NET Core or Angular, React, and Vue applications with .NET backend. Dashboards allow you to display multiple inter-connected data analysis elements such as grids, charts, maps, gauges, and others: all within an automatically-arranged layout.

The set of components allows you to deploy an all-in-one solution and switch between Viewer and Designer modes directly on the web client (includes adaptive layouts for tablet & mobile).

The Web Dashboard is available as a part of a Universal subscription.

Get Started with DevExpress BI Dashboard | Explore Demos

This tutorial shows how to add the DataGrid to a page, bind it to data, and configure its core features. As a result, you will get a UI component that looks as follows:

Each section in this tutorial covers a single configuration step. You can also find the full code in the GitHub repository.

View on GitHub

Create a DataGrid

jQuery

Add DevExtreme to your jQuery application and use the following code to create a DataGrid:

Angular

Add DevExtreme to your Angular application and use the following code to create a DataGrid:

Vue

Add DevExtreme to your Vue application and use the following code to create a DataGrid:

React

Add DevExtreme to your React application and use the following code to create a DataGrid:

jQuery
index.js
index.html
index.css
$(function() {
    $("#dataGrid").dxDataGrid({
        // Configuration goes here
    });
});
<html>
    <head>
        <!-- ... -->
        <script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

        <link rel="stylesheet" href="https://cdn3.devexpress.com/jslib/26.1.4/css/dx.light.css">
        <link rel="stylesheet" href="index.css">

        <script type="text/javascript" src="https://cdn3.devexpress.com/jslib/26.1.4/js/dx.all.js"></script>
        <script type="text/javascript" src="index.js"></script>
    </head>
    <body class="dx-viewport">
        <div id="dataGrid"></div>
    </body>
</html>
#dataGrid {
    height: 500px;
}
ASP.NET Core Controls
Index.cshtml
Site.css
@(Html.DevExtreme().DataGrid()
    .ID("grid-container")
)
#grid-container {
    height: 500px;
}
Angular
app.component.html
app.component.ts
app.module.ts
app.component.css
<dx-data-grid id="dataGrid"
    <!-- Configuration goes here -->
>
</dx-data-grid>
import { Component } from '@angular/core';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent {

}
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';

import { DxDataGridModule } from 'devextreme-angular';

@NgModule({
    declarations: [
        AppComponent
    ],
    imports: [
        BrowserModule,
        DxDataGridModule
    ],
    providers: [ ],
    bootstrap: [AppComponent]
})
export class AppModule { }
#dataGrid {
    height: 500px;
}
Vue
App.vue
<template>
    <div id="app-container">
        <DxDataGrid id="dataGrid">
            <!-- Configuration goes here -->
        </DxDataGrid>
    </div>
</template>

<script>
import 'devextreme/dist/css/dx.fluent.blue.light.css';

import { DxDataGrid } from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid
    }
}
</script>

<style>
#dataGrid {
    height: 500px;
}
</style>
React
App.tsx
App.css
import React from 'react';
import 'devextreme/dist/css/dx.fluent.blue.light.css';

import { DataGrid } from 'devextreme-react/data-grid';

function App() {
    return (
        <div className="App">
            <DataGrid id="dataGrid">
                {/* Configuration goes here */}
            </DataGrid>
        </div>
    );
}

export default App;
#dataGrid {
    height: 500px;
}

Bind the DataGrid to Data

DataGrid can load and update data from different data source types. To use a local array, assign the array to dataSource and specify the key field in keyExpr.

The following code snippet initializes a DataGrid and creates columns for all data fields. All columns are equal width, and the column order follows the data source structure.

jQuery
index.js
data.js
$(function() {
    $("#dataGrid").dxDataGrid({
        dataSource: employees,
        keyExpr: "EmployeeID",
    });
});
const employees = [
    // ...
];
ASP.NET Core Controls
Index.cshtml
EmployeeDataController.cs
Employee.cs
EmployeeData.cs
@using ASP_NET_Core.Models

@(Html.DevExtreme().DataGrid<Employee>()
    .ID("grid-container")
    .DataSource(d => d
        .Mvc().Controller("EmployeeData")
        .LoadAction("Get")
        .Key("EmployeeID")
    )
)
using ASP_NET_Core.Models;
using DevExtreme.AspNet.Data;
using DevExtreme.AspNet.Mvc;
using Microsoft.AspNetCore.Mvc;

namespace ASP_NET_Core.Controllers;

public class EmployeeDataController : Controller {

    [HttpGet]
    public object Get(DataSourceLoadOptions loadOptions) {
        return DataSourceLoader.Load(EmployeeData.Employees, loadOptions);
    }

}
namespace ASP_NET_Core.Models;
public class Employee {
    public int EmployeeID { get; set; }
    public string FullName { get; set; }
    public string Position { get; set; }
    public string TitleOfCourtesy { get; set; }
    public string BirthDate { get; set; }
    public string HireDate { get; set; }
    public string Address { get; set; }
    public string City { get; set; }
    public string Region { get; set; }
    public string PostalCode { get; set; }
    public string Country { get; set; }
    public string HomePhone { get; set; }
    public string Extension { get; set; }
    public string Photo { get; set; }
    public string Notes { get; set; }
    public int? ReportsTo { get; set; }
}
namespace ASP_NET_Core.Models;
static class EmployeeData {
    public static List<Employee> Employees = [
        // ...
    ];
}
Angular
app.component.html
app.component.ts
employees.service.ts
<dx-data-grid
    [dataSource]="employees"
    keyExpr="EmployeeID">
</dx-data-grid>
import { Component } from '@angular/core';
import { Employee, EmployeesService } from './employees.service';

// ...
export class AppComponent {
    employees: Employee[] = [];

    constructor(service: EmployeesService) {
        this.employees = service.getEmployees();
    }
}
import { Injectable } from '@angular/core';

export interface Employee {
    EmployeeID: number;
    FullName: string;
    Position: string;
    TitleOfCourtesy: string;
    BirthDate: string;
    HireDate: string;
    Address: string;
    City: string;
    Region: string;
    PostalCode: string;
    Country: string;
    HomePhone: string;
    Extension: string;
    Photo: string;
    Notes: string;
    ReportsTo: number | null;
}

const employees: Employee[] = [
    // ...
];

@Injectable({
    providedIn: 'root'
})
export class EmployeesService {
    getEmployees(): Employee[] {
        return employees;
    }
}
Vue
App.vue
employees.service.ts
<template>
    <div id="app-container">
        <DxDataGrid
            :data-source="employees"
            key-expr="EmployeeID">
        </DxDataGrid>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { getEmployees, type Employee } from './employees.service';

const employees = ref<Employee[]>(getEmployees());
</script>
export interface Employee {
    EmployeeID: number;
    FullName: string;
    Position: string;
    TitleOfCourtesy: string;
    BirthDate: string;
    HireDate: string;
    Address: string;
    City: string;
    Region: string | null;
    PostalCode: string;
    Country: string;
    HomePhone: string;
    Extension: string;
    Photo: string;
    Notes: string;
    ReportsTo: number | null;
}

const employees = [
    // ...
];

export function getEmployees(): Employee[] {
    return employees;
}
React
App.tsx
employees.ts
// ...
import { employees } from './employees';

function App() {
    return (
        <div className="App">
            <DataGrid
                dataSource={employees}
                keyExpr="EmployeeID">
            </DataGrid>
        </div>
    );
}
export interface Employee {
    EmployeeID: number;
    FullName: string;
    Position: string;
    TitleOfCourtesy: string;
    BirthDate: string;
    HireDate: string;
    Address: string;
    City: string;
    Region: string | null;
    PostalCode: string;
    Country: string;
    HomePhone: string;
    Extension: string;
    Photo: string;
    Notes: string;
    ReportsTo: number | null;
}

export const employees = [
    // ...
];

To use another data source type, refer to the following help topics:

Customize Columns

Read Tutorial: Columns - Overview

jQuery

Use the columns array to define and customize DataGrid columns. Configure columns as objects to specify options. To add columns with default options, add dataField values to columns[] as strings.

Angular

Specify the columns array to define and customize DataGrid columns. Specify each column's dataField value.

Vue

Specify the columns array to define and customize DataGrid columns. To add a column, specify the dataField value.

React

Specify the columns array to define and customize DataGrid columns. To add a column, specify the dataField value.

Reorder Columns

Read Tutorial: Column Reordering

To set the initial column order, arrange items in the columns[] array as needed. Enable allowColumnReordering to allow users to reorder columns in the component UI.

The following code snippet also specifies dataType for BirthDate and HireDate columns to display string values as dates:

jQuery
index.js
$("#dataGrid").dxDataGrid({
    columns: [{
        dataField: "FullName"
    }, {
        dataField: "Position"
    }, {
        dataField: "BirthDate", 
        dataType: "date",
    }, {
        dataField: "HireDate", 
        dataType: "date",
    },"City", {
        dataField: "Country"
    },
    "Address",
    "HomePhone",
    {
        dataField: "PostalCode",
    }],
    allowColumnReordering: true,
});
ASP.NET Core Controls
Index.cshtml
@(Html.DevExtreme().DataGrid<Employee>()
    .Columns(columns => {
        columns.AddFor(m => m.FullName);
        columns.AddFor(m => m.Position);
        columns.AddFor(m => m.BirthDate)
            .DataType(GridColumnDataType.Date);
        columns.AddFor(m => m.HireDate)
            .DataType(GridColumnDataType.Date);
        columns.AddFor(m => m.Country);
        columns.AddFor(m => m.Address);
        columns.AddFor(m => m.HomePhone);
        columns.AddFor(m => m.PostalCode);
    })
    @* ... *@
)
Angular
app.component.html
<dx-data-grid [allowColumnReordering]="true">
    <dxi-data-grid-column dataField="FullName"></dxi-data-grid-column>
    <dxi-data-grid-column dataField="Position"></dxi-data-grid-column>
    <dxi-data-grid-column
        dataField="BirthDate"
        dataType="date">
    </dxi-data-grid-column>
    <dxi-data-grid-column
        dataField="HireDate"
        dataType="date">
    </dxi-data-grid-column>
    <dxi-data-grid-column dataField="City"></dxi-data-grid-column>
    <dxi-data-grid-column dataField="Country"></dxi-data-grid-column>
    <dxi-data-grid-column dataField="Address"></dxi-data-grid-column>
    <dxi-data-grid-column dataField="HomePhone"></dxi-data-grid-column>
    <dxi-data-grid-column dataField="PostalCode"></dxi-data-grid-column>
</dx-data-grid>
Vue
App.vue
<template>
    <DxDataGrid :allow-column-reordering="true">
        <DxColumn data-field="FullName"></DxColumn>
        <DxColumn data-field="Position"></DxColumn>
        <DxColumn
            data-field="BirthDate"
            data-type="date">
        </DxColumn>
        <DxColumn
            data-field="HireDate"
            data-type="date">
        </DxColumn>
        <DxColumn data-field="City" />
        <DxColumn data-field="Country"></DxColumn>
        <DxColumn data-field="Address" />
        <DxColumn data-field="HomePhone" />
        <DxColumn data-field="PostalCode" />
    </DxDataGrid>
</template>

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

</script>
React
App.tsx
import { DataGrid, Column } from 'devextreme-react/data-grid';

function App() {
    return (
        <DataGrid allowColumnReordering={true}>
            <Column dataField="FullName"></Column>
            <Column dataField="Position"></Column>
            <Column
                dataField="BirthDate"
                dataType="date">
            </Column>
            <Column
                dataField="HireDate"
                dataType="date">
            </Column>
            <Column dataField="City" />
            <Column dataField="Country"></Column>
            <Column dataField="Address" />
            <Column dataField="HomePhone" />
            <Column dataField="PostalCode" />
        </DataGrid>
    );
}

Resize Columns

Read Tutorial: Column Sizing

DataGrid columns have equal widths in the default configuration (width is set to "auto"). To change the column layout, you can define each column's width property or enable columnAutoWidth to adjust all columns to fit cell values. To allow users to change the column layout, enable allowColumnResizing.

jQuery
index.js
$("#dataGrid").dxDataGrid({
    allowColumnResizing: true,
    columnAutoWidth: true,
    columns: [{
        dataField: "BirthDate", 
        dataType: "date",
        width: 100,
    }, {
        dataField: "HireDate", 
        dataType: "date",
        width: 100,
    }, /* ... */ ],
    // ...
});
ASP.NET Core Controls
Index.cshtml
@(Html.DevExtreme().DataGrid<Employee>()
    .AllowColumnResizing(true)
    .ColumnAutoWidth(true)
    .Columns(columns => {
        columns.AddFor(m => m.BirthDate)
            .DataType(GridColumnDataType.Date)
            .Width(100);
        columns.AddFor(m => m.HireDate)
            .DataType(GridColumnDataType.Date)
            .Width(100);
    })
    @* ... *@
)
Angular
app.component.html
<dx-data-grid
    [allowColumnResizing]="true"
    [columnAutoWidth]="true"
>
    <dxi-data-grid-column
        dataField="BirthDate"
        dataType="date"
        [width]="100"
    ></dxi-data-grid-column>
    <dxi-data-grid-column
        dataField="HireDate"
        dataType="date"
        [width]="100"
    ></dxi-data-grid-column>
    <!-- ... -->
</dx-data-grid>
Vue
App.vue
<template>
    <DxDataGrid
        :allow-column-resizing="true"
        :column-auto-width="true"
    >
        <DxColumn
            data-field="BirthDate"
            data-type="date"
            :width="100"
        />
        <DxColumn
            data-field="HireDate"
            data-type="date"
            :width="100"
        />
        <!-- ... -->
    </DxDataGrid>
</template>

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

</script>
React
App.tsx
import { DataGrid, Column } from 'devextreme-react/data-grid';

function App() {
    return (
        <DataGrid
            columnAutoWidth={true}
            allowColumnResizing={true}
        >
            <Column
                dataField="BirthDate"
                dataType="date"
                width={100}
            />
            <Column
                dataField="HireDate"
                dataType="date"
                width={100}
            />
            {/* ... */}
        </DataGrid>
    );
}

Fix Columns

Read Tutorial: Column Fixing

When the total column width exceeds the UI component width, a horizontal scroll bar appears. To keep specific columns visible, enable columnFixing. Set columns[].fixed to true to fix a column. Set fixedPosition to specify the fixed column position or create a sticky column. Users can also change column fixing options in the DataGrid context menu.

jQuery
index.js
$("#dataGrid").dxDataGrid({
    columnFixing: { enabled: true },
    columns: [{
        dataField: "FullName", 
        fixed: true
    }, /* ... */ ],
    // ...
});
ASP.NET Core Controls
Index.cshtml
@(Html.DevExtreme().DataGrid<Employee>()
    .ColumnFixing(c => c.Enabled(true))
    .Columns(columns => {
        columns.AddFor(m => m.FullName)
            .Fixed(true);
    })
    @* ... *@
)
Angular
app.component.html
<dx-data-grid>
    <dxo-data-grid-column-fixing [enabled]="true"></dxo-data-grid-column-fixing>
    <dxi-data-grid-column
        dataField="FullName"
        [fixed]="true"
    ></dxi-data-grid-column>
    <!-- ... -->
</dx-data-grid>
Vue
App.vue
<template>
    <DxDataGrid>
        <DxColumnFixing :enabled="true" />
        <DxColumn
            data-field="FullName"
            :fixed="true"
        />
        <!-- ... -->
    </DxDataGrid>
</template>

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

</script>
React
App.tsx
import { DataGrid, ColumnFixing, Column } from 'devextreme-react/data-grid';

function App() {
    return (
        <div className="App">
            <DataGrid>
                <ColumnFixing enabled={true} />
                <Column
                    dataField="FullName"
                    fixed={true}
                />
                {/* ... */}
            </DataGrid>
        </div>
    );
}

Hide Columns

Read Tutorial: Hide a Column Using the API Read Tutorial: Column Chooser

To hide a DataGrid column, set columns[].visible to false. If the columnChooser is enabled, users can restore hidden columns. To hide a column in both the component and the column chooser, omit the corresponding columns[] item.

jQuery
index.js
$("#dataGrid").dxDataGrid({
    columnChooser: { enabled: true },
    columns: [{
        dataField: "PostalCode",
        visible: false
    }, /* ... */ ],
    // ...
});
ASP.NET Core Controls
Index.cshtml
@(Html.DevExtreme().DataGrid<Employee>()
    .ColumnChooser(c => c.Enabled(true))
    .Columns(columns => {
        columns.AddFor(m => m.PostalCode)
            .Visible(false);
    })
    @* ... *@
)
Angular
app.component.html
<dx-data-grid>
    <dxo-data-grid-column-chooser [enabled]="true"></dxo-data-grid-column-chooser>
    <dxi-data-grid-column
        dataField="PostalCode"
        [visible]="false"
    ></dxi-data-grid-column>
    <!-- ... -->
</dx-data-grid>
Vue
App.vue
<template>
    <DxDataGrid ... >
        <DxColumnChooser :enabled="true" />
        <DxColumn
            data-field="PostalCode"
            :visible="false"
        />
        <!-- ... -->
    </DxDataGrid>
</template>

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

</script>
React
App.tsx
import { DataGrid, ColumnChooser, Column } from 'devextreme-react/data-grid';

function App() {
    return (
        <DataGrid ... >
            <ColumnChooser enabled={true} />
            <Column
                dataField="PostalCode"
                visible={false}
            />
            {/* ... */}
        </DataGrid>
    );
}

Sort Data

Read Tutorial: DataGrid - Sorting

The sorting.mode property specifies whether users can sort grid records against single or multiple columns.

You can also set a column's sortOrder and sortIndex properties to specify initial sorting settings. sortIndex applies only in multi-column sort mode.

To sort data and change sort orders in the UI, click column headers. Hold Shift and click to sort data against multiple columns.

jQuery
index.js
$("#dataGrid").dxDataGrid({
    sorting: { mode: "multiple" },
    columns: [{
        dataField: "Country",
        sortOrder: "asc",
    }, /* ... */ ],
    // ...
});
ASP.NET Core Controls
Index.cshtml
@(Html.DevExtreme().DataGrid<Employee>()
    .Sorting(s => s.Mode(GridSortingMode.Multiple))
    .Columns(columns => {
        columns.AddFor(m => m.Country)
            .SortOrder(SortOrder.Asc);
    })
    @* ... *@
)
Angular
app.component.html
<dx-data-grid>
    <dxo-sorting mode="multiple"></dxo-sorting>
    <dxi-data-grid-column
        dataField="Country"
        sortOrder="asc"
    ></dxi-data-grid-column>
    <!-- ... -->
</dx-data-grid>
Vue
App.vue
<template>
    <DxDataGrid ... >
        <DxSorting mode="multiple" />
        <DxColumn
            data-field="Country"
            sort-order="asc"
        />
        <!-- ... -->
    </DxDataGrid>
</template>

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

</script>
React
App.tsx
import { DataGrid, Sorting, Column } from 'devextreme-react/data-grid';

function App() {
    return (
        <div className="App">
            <DataGrid ... >
                <Sorting mode="multiple" />
                <Column
                    dataField="Country"
                    sortOrder="asc"
                />
                {/* ... */}
            </DataGrid>
        </div>
    );
}

Filter and Search Data

Read Tutorial: DataGrid - Filtering and Searching

DataGrid includes the following UI elements used to filter and search data:

This tutorial uses the filterRow and searchPanel:

jQuery
index.js
$("#dataGrid").dxDataGrid({
    filterRow: { visible: true },
    searchPanel: { visible: true },
    // ...
});
ASP.NET Core Controls
Index.cshtml
@(Html.DevExtreme().DataGrid<Employee>()
    .FilterRow(f => f.Visible(true))
    .SearchPanel(s => s.Visible(true))
    @* ... *@
)
Angular
app.component.html
<dx-data-grid>
    <dxo-data-grid-filter-row [visible]="true"></dxo-data-grid-filter-row>
    <dxo-data-grid-search-panel [visible]="true"></dxo-data-grid-search-panel>
    <!-- ... -->
</dx-data-grid>
Vue
App.vue
<template>
    <DxDataGrid ... >
        <DxFilterRow :visible="true" />
        <DxSearchPanel :visible="true" />
        <!-- ... -->
    </DxDataGrid>
</template>

<script setup lang="ts">
import { DxDataGrid, DxFilterRow, DxSearchPanel } from 'devextreme-vue/data-grid';

</script>
React
App.tsx
import { DataGrid, FilterRow, SearchPanel } from 'devextreme-react/data-grid';

function App() {
    return (
        <DataGrid ... >
            <FilterRow visible={true} />
            <SearchPanel visible={true} />
            {/* ... */}
        </DataGrid>
    );
}

Group Data

Read Tutorial: DataGrid - Grouping

You can group DataGrid records against single or multiple columns. To group records in the UI, right-click column headers if grouping.contextMenuEnabled is true (default). You can also drag and drop column headers onto the group panel if groupPanel.visible is true.

To group data in code, define columns[].groupIndex property. This tutorial specifies groupIndex for the Country column:

jQuery
index.js
$("#dataGrid").dxDataGrid({
    groupPanel: { visible: true },
    columns: [{
        dataField: "Country",
        groupIndex: 0,
    }, /* ... */ ],
    // ...
});
ASP.NET Core Controls
Index.cshtml
@(Html.DevExtreme().DataGrid<Employee>()
    .GroupPanel(p => p.Visible(true))
    .Columns(columns => {
        columns.AddFor(m => m.Country)
            .GroupIndex(0);
    })
    @* ... *@
)
Angular
app.component.html
<dx-data-grid>
    <dxo-data-grid-group-panel [visible]="true"></dxo-data-grid-group-panel>
    <dxi-data-grid-column
        dataField="Country"
        [groupIndex]="0"
    ></dxi-data-grid-column>
    <!-- ... -->
</dx-data-grid>
Vue
App.vue
<template>
    <DxDataGrid>
        <DxGroupPanel :visible="true" />
        <DxColumn
            data-field="Country"
            :group-index="0"
        />
        <!-- ... -->
    </DxDataGrid>
</template>

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

</script>
React
App.tsx
import { DataGrid, GroupPanel, Column } from 'devextreme-react/data-grid';

function App() {
    return (
        <DataGrid>
            <GroupPanel visible={true} />
            <Column
                dataField="Country"
                groupIndex={0}
            />
            {/* ... */}
        </DataGrid>
    );
}

Edit and Validate Data

Read Tutorial: DataGrid - Editing

Users can add new records and update or delete existing records. To allow these operations, enable the following editing options:

DataGrid supports multiple edit modes. This tutorial uses the pop-up edit mode.

This tutorial also implements data validation to check that edited data is valid before saving. Required rules are configured to ensure certain column values are never empty:

jQuery
index.js
$("#dataGrid").dxDataGrid({
    editing: {
        mode: "popup",
        allowUpdating: true,
        allowDeleting: true,
        allowAdding: true
    },
    columns: [{
        dataField: "FullName",
        validationRules: [{ type: "required" }]
    }, {
        dataField: "Position",
        validationRules: [{ type: "required" }]
    }, {
        dataField: "BirthDate",
        validationRules: [{ type: "required" }]
    }, {
        dataField: "HireDate", 
        validationRules: [{ type: "required" }]
    }, {
        dataField: "Country",
        validationRules: [{ type: "required" }]
    }, /* ... */ ],
    // ...
});
ASP.NET Core Controls
Index.cshtml
@(Html.DevExtreme().DataGrid<Employee>()
    .Editing(e => e
        .Mode(GridEditMode.Popup)
        .AllowAdding(true)
        .AllowDeleting(true)
        .AllowUpdating(true)
    )
    .Columns(columns => {
        columns.AddFor(m => m.FullName)
            .ValidationRules(v => v.AddRequired());
        columns.AddFor(m => m.Position)
            .ValidationRules(v => v.AddRequired());
        columns.AddFor(m => m.BirthDate)
            .ValidationRules(v => v.AddRequired());
        columns.AddFor(m => m.HireDate)
            .ValidationRules(v => v.AddRequired());
        columns.AddFor(m => m.Country)
            .ValidationRules(v => v.AddRequired());
    })
    @* ... *@
)
Angular
app.component.html
<dx-data-grid>
    <dxo-data-grid-editing
        mode="popup"
        [allowUpdating]="true"
        [allowDeleting]="true"
        [allowAdding]="true"
    ></dxo-data-grid-editing>
    <dxi-data-grid-column dataField="FullName">
        <dxi-data-grid-validation-rule type="required"></dxi-data-grid-validation-rule>
    </dxi-data-grid-column>
    <dxi-data-grid-column dataField="Position">
        <dxi-data-grid-validation-rule type="required"></dxi-data-grid-validation-rule>
    </dxi-data-grid-column>
    <dxi-data-grid-column dataField="BirthDate">
        <dxi-data-grid-validation-rule type="required"></dxi-data-grid-validation-rule>
    </dxi-data-grid-column>
    <dxi-data-grid-column dataField="HireDate">
        <dxi-data-grid-validation-rule type="required"></dxi-data-grid-validation-rule>
    </dxi-data-grid-column>
    <dxi-data-grid-column dataField="Country">
        <dxi-data-grid-validation-rule type="required"></dxi-data-grid-validation-rule>
    </dxi-data-grid-column>
    <!-- ... -->
</dx-data-grid>
Vue
App.vue
<template>
    <DxDataGrid>
        <DxEditing
            mode="popup"
            :allow-updating="true"
            :allow-adding="true"
            :allow-deleting="true"
        />
        <DxColumn data-field="FullName">
            <DxRequiredRule />
        </DxColumn>
        <DxColumn data-field="Position">
            <DxRequiredRule />
        </DxColumn>
        <DxColumn data-field="BirthDate">
            <DxRequiredRule />
        </DxColumn>
        <DxColumn data-field="HireDate">
            <DxRequiredRule />
        </DxColumn>
        <DxColumn data-field="Country">
            <DxRequiredRule />
        </DxColumn>
        <!-- ... -->
    </DxDataGrid>
</template>

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

</script>
React
App.tsx
import { DataGrid, Editing, Column, RequiredRule } from 'devextreme-react/data-grid';

function App() {
    return (
        <DataGrid>
            <Editing
                mode="popup"
                allowUpdating={true}
                allowDeleting={true}
                allowAdding={true}
            />
            <Column dataField="FullName">
                <RequiredRule />
            </Column>
            <Column dataField="Position">
                <RequiredRule />
            </Column>
            <Column dataField="BirthDate">
                <RequiredRule />
            </Column>
            <Column dataField="HireDate">
                <RequiredRule />
            </Column>
            <Column dataField="Country">
                <RequiredRule />
            </Column>
            {/* ... */}
        </DataGrid>
    );
}

To implement validation for unchanged cells using a custom toolbar button, refer to the following example:

View on GitHub

Select Records

Read Tutorial: DataGrid - Selection

DataGrid supports single- and multiple-row selection. To enable row selection, configure the selection.mode property.

Handle onSelectionChanged to obtain selected records at runtime. This tutorial uses onSelectionChanged to display selected employee names in an element outside the component:

jQuery
index.js
index.html
$("#dataGrid").dxDataGrid({
    selection: { mode: "single" },
    onSelectionChanged: function(e) {
        e.component.byKey(e.currentSelectedRowKeys[0]).done(employee => {
            if(employee) {
                $("#selected-employee").text(`Selected employee: ${employee.FullName}`);
            }
        });
    },
    // ...
});
<html>
    <!-- ... -->
    <body class="dx-viewport">
        <div id="app-container">
            <div id="dataGrid"></div>
            <p id="selected-employee"></p>
        </div>
    </body>
</html>
ASP.NET Core Controls
Index.cshtml
<div id="app-container">
    @(Html.DevExtreme().DataGrid<Employee>()
        .Selection(s => s.Mode(SelectionMode.Single))
        .OnSelectionChanged("handleSelectionChanged")
        @* ... *@
    )
    <p id="selected-employee"></p>
</div>

<script>
    function handleSelectionChanged(e) {
        e.component.byKey(e.currentSelectedRowKeys[0]).done((employee) => {
            if (employee) {
                $('#selected-employee').text(`Selected employee: ${employee.FullName}`);
            }
        });
    }
</script>
Angular
app.component.html
app.component.ts
<div id="app-container">
    <dx-data-grid (onSelectionChanged)="selectEmployee($event)">
        <dxo-data-grid-selection mode="single"></dxo-data-grid-selection>
        <!-- ... -->
    </dx-data-grid>
    @if (selectedEmployee) {
        <p id="selected-employee">
            Selected employee: {{ selectedEmployee.FullName }}
        </p>
    }
</div>
import { Component } from '@angular/core';
import { DxDataGridTypes } from 'devextreme-angular/ui/data-grid';
import { Employee, EmployeesService } from './employees.service';

// ...
export class AppComponent {
    selectedEmployee: Employee;

    constructor(service: EmployeesService) {
        this.selectEmployee = this.selectEmployee.bind(this);
    }

    selectEmployee(e: DxDataGridTypes.SelectionChangedEvent) {
        e.component.byKey(e.currentSelectedRowKeys[0]).done(employee => {
            if(employee) {
                this.selectedEmployee = employee;
            }
        });
    }
}
Vue
App.vue
<template>
    <div id="app-container">
        <DxDataGrid @selection-changed="selectEmployee">
            <DxSelection mode="single" />
            <!-- ... -->
        </DxDataGrid>
        <p id="selected-employee" v-if="selectedEmployee">
            Selected employee: {{ selectedEmployee.FullName }}
        </p>
    </div>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { DxDataGrid, DxSelection, type DataGridTypes } from 'devextreme-vue/data-grid';
import { type Employee } from '../employees.service';

const selectedEmployee = ref<Employee | undefined>();

function selectEmployee(e: DataGridTypes.SelectionChangedEvent): void {
    e.component.byKey(e.currentSelectedRowKeys[0]).done((employee: Employee) => {
        if (employee) {
            selectedEmployee.value = employee;
        }
    });
}
</script>
React
App.tsx
import React, { useCallback, useState } from 'react';
import { DataGrid, Selection, type DataGridTypes } from 'devextreme-react/data-grid';
import { type Employee } from './employees';

function SelectedEmployee(props) {
    if(props.employee) {
        return (
            <p id="selected-employee">
                Selected employee: {props.employee.FullName}
            </p>
        );
    }
    return null;
}

function App() {
    const [selectedEmployee, setSelectedEmployee] = useState();
    const selectEmployee = useCallback((e: DataGridTypes.SelectionChangedEvent): void => {
        e.component.byKey(e.currentSelectedRowKeys[0]).then((employee: Employee) => {
            setSelectedEmployee(employee);
        }).catch(() => {});
    }, []);

    return (
        <div className="App">
            <DataGrid onSelectionChanged={selectEmployee}>
                <Selection mode="single" />
                {/* ... */}
            </DataGrid>
            <SelectedEmployee employee={selectedEmployee} />
        </div>
    );
}

Display Summaries

Read Tutorial: DataGrid - Total Summary Read Tutorial: DataGrid - Group Summary

DataGrid supports two types of data summaries:

  • Total summaries: Calculated against all grid records. Configured in the totalItems array.
  • Group summaries: Calculated for each data group. Configured in the groupItems array.

Each summary item applies an aggregate function specified in summaryType to display summarized values. You can use predefined aggregate functions (such as "sum", "avg", and "count") or define a custom aggregate function. This tutorial displays a "count" group summary:

jQuery
index.js
$("#dataGrid").dxDataGrid({
    summary: {
        groupItems: [{
            summaryType: "count"
        }]
    },
    // ...
});
ASP.NET Core Controls
Index.cshtml
@(Html.DevExtreme().DataGrid<Employee>()
    .Summary(s => s
        .GroupItems(groupItems => {
            groupItems.Add().SummaryType(SummaryType.Count);
        })
    )
    @* ... *@
)
Angular
app.component.html
<dx-data-grid>
    <dxo-data-grid-summary>
        <dxi-data-grid-group-item
            summaryType="count">
        </dxi-data-grid-group-item>
    </dxo-data-grid-summary>
    <!-- ... -->
</dx-data-grid>
Vue
App.vue
<template>
    <DxDataGrid>
        <DxSummary>
            <DxGroupItem summary-type="count" />
        </DxSummary>
        <!-- ... -->
    </DxDataGrid>
</template>

<script setup lang="ts">
import { DxDataGrid, DxSummary, DxGroupItem } from 'devextreme-vue/data-grid';

</script>
React
App.tsx
import { DataGrid, Summary, GroupItem } from 'devextreme-react/data-grid';

function App() {
    return (
        <div className="App">
            <DataGrid>
                <Summary>
                    <GroupItem summaryType="count" />
                </Summary>
                {/* ... */}
            </DataGrid>
        </div>
    );
}

Customize the Toolbar

The DataGrid includes an integrated toolbar that displays predefined and custom controls. To add or remove toolbar items, declare the toolbar.items[] array. Toolbar items within the UI preserve the order in which they are declared.

This tutorial illustrates how to add the following items to the toolbar:

  • Predefined controls
    Declare a toolbar item element and specify the name and properties that you want to customize (see the "addRowButton" configuration in the code below). If a control does not need customization, include its name only. Ensure that items[] contain controls for all features that you enabled in your DataGrid.

  • DevExtreme components
    Configure a DevExtreme component within a toolbar item element. In this tutorial, we extended the toolbar's item collection with a custom Button that expands or collapses all grid records.

IMPORTANT
If you add custom items to the DataGrid toolbar, you must also specify the built-in items you need.
jQuery
index.js
const dataGrid = $("#dataGrid").dxDataGrid({
    toolbar: {
        items: [
            "groupPanel", {
                location: "after",
                widget: "dxButton",
                options: {
                    text: "Collapse All",
                    width: 136,
                    onClick(e) {
                        const expanding = e.component.option("text") === "Expand All";
                        dataGrid.option("grouping.autoExpandAll", expanding);
                        e.component.option("text", expanding ? "Collapse All" : "Expand All");
                    },
                },
            }, {
                name: "addRowButton",
                showText: "always"
            }, "exportButton", "columnChooserButton", "searchPanel",
        ]
    },
    // ...
}).dxDataGrid("instance");
ASP.NET Core Controls
Index.cshtml
@(Html.DevExtreme().DataGrid<Employee>()
    .ID("grid-container")
    .Toolbar(t => t.Items(items => {
        items.Add().Name(DataGridToolbarItem.GroupPanel);
        items.Add()
            .Location(ToolbarItemLocation.After)
            .Widget(w => w.Button()
                .Text("Collapse All")
                .Width(136)
                .OnClick("handleCollapseAllButtonClick")
        );
        items.Add().Name(DataGridToolbarItem.AddRowButton).ShowText(ToolbarItemShowTextMode.Always);
        items.Add().Name(DataGridToolbarItem.ExportButton);
        items.Add().Name(DataGridToolbarItem.ColumnChooserButton);
        items.Add().Name(DataGridToolbarItem.SearchPanel);
    }))
    @* ... *@
)

<script>
    function handleCollapseAllButtonClick(e) {
        const expanding = e.component.option('text') === 'Expand All';
        $('#grid-container').dxDataGrid('instance').option('grouping.autoExpandAll', expanding);
        e.component.option('text', expanding ? 'Collapse All' : 'Expand All');
    }
</script>
Angular
app.component.html
app.component.ts
app.module.ts
<dx-data-grid ... >
    <dxo-data-grid-grouping [autoExpandAll]="expanded"></dxo-data-grid-grouping>
    <dxo-data-grid-toolbar>
        <dxi-data-grid-item name="groupPanel"></dxi-data-grid-item>
        <dxi-data-grid-item location="after">
            <dx-button
                [text]="expanded ? 'Collapse All' : 'Expand All'"
                [width]="136"
                (onClick)="expanded = !expanded">
            </dx-button>
        </dxi-data-grid-item>
        <dxi-data-grid-item name="addRowButton" showText="always"></dxi-data-grid-item>
        <dxi-data-grid-item name="exportButton"></dxi-data-grid-item>
        <dxi-data-grid-item name="columnChooserButton"></dxi-data-grid-item>
        <dxi-data-grid-item name="searchPanel"></dxi-data-grid-item>
    </dxo-data-grid-toolbar>
    <!-- ... -->
</dx-data-grid>
// ...
export class AppComponent {
    // ...
    expanded: boolean = true;
}
import {
    // ...
    DxButtonModule
} from 'devextreme-angular';

@NgModule({
    // ...
    imports: [
        // ...
        DxButtonModule
    ],
})
export class AppModule { }
Vue
App.vue
<template>
    <DxDataGrid ... >
        <DxGrouping :auto-expand-all="expanded" />
        <DxToolbar>
            <DxItem name="groupPanel" />
            <DxItem location="after" template="button-template" />
            <DxItem name="addRowButton" show-text="always" />
            <DxItem name="exportButton" />
            <DxItem name="columnChooserButton" />
            <DxItem name="searchPanel" />
        </DxToolbar>
        <template #button-template>
            <DxButton
                :text="expanded ? 'Collapse All' : 'Expand All'"
                :width="136"
                @click="expanded = !expanded"
            />
        </template>
        <!-- ... -->
    </DxDataGrid>
</template>

<script setup lang="ts">
import { ref } from 'vue';
import { DxDataGrid, DxGrouping, DxToolbar, DxItem } from 'devextreme-vue/data-grid';
import { DxButton } from 'devextreme-vue/button';

const expanded = ref<boolean>(true);

</script>
React
App.tsx
import { DataGrid, Grouping, Toolbar, Item } from 'devextreme-react/data-grid';
import { Button } from 'devextreme-react/button';

function App() {
    const [expanded, setExpanded] = useState(true);

    return (
        <DataGrid>
            <Grouping autoExpandAll={expanded} />
            <Toolbar>
                <Item name="groupPanel" />
                <Item location="after">
                    <Button
                        text={expanded ? 'Collapse All' : 'Expand All'}
                        width={136}
                        onClick={() => setExpanded(prevExpanded => !prevExpanded)}
                    />
                </Item>
                <Item name="addRowButton" showText="always" />
                <Item name="exportButton" />
                <Item name="columnChooserButton" />
                <Item name="searchPanel" />
            </Toolbar>
            {/* ... */}
        </DataGrid>
    );
}

Configure Master-Detail Interface

Read Tutorial: DataGrid - Master-Detail Interface

DataGrid supports master-detail data presentation. You can display detail data in expandable sections below master rows. To configure master-detail mode, set masterDetail.enabled to true and specify a template. This tutorial configures a template that displays employee images from file paths stored in the component data source:

jQuery
index.js
$("#dataGrid").dxDataGrid({
    masterDetail: {
        enabled: true,
        template: function (_, options) {
            const employee = options.data;
            const photo = $("<img>")
                .addClass("employee-photo")
                .attr("src", employee.Photo);
            const notes = $("<p>")
                .addClass("employee-notes")
                .text(employee.Notes);
            return $("<div>").append(photo, notes);
        }
    },
    // ...
});
ASP.NET Core Controls
Index.cshtml
@(Html.DevExtreme().DataGrid<Employee>()
    .MasterDetail(m => m
        .Enabled(true)
        .Template(new JS ("masterDetailTemplate"))
    )
    @* ... *@
)

<script>
    function masterDetailTemplate(_, options) {
        const employee = options.data;
        const photo = $('<img>').addClass('employee-photo').attr('src', employee.Photo);
        const notes = $('<p>').addClass('employee-notes').text(employee.Notes);
        return $('<div>').append(photo, notes);
    }
</script>
Angular
app.component.html
<dx-data-grid>
    <dxo-data-grid-master-detail
        [enabled]="true"
        [template]="'employee-info'">
    </dxo-data-grid-master-detail>
    <div *dxTemplate="let employee of 'employee-info'">
        <img class="employee-photo" [src]="employee.data.Photo">
        <p class="employee-notes">{{ employee.data.Notes }}</p>
    </div>
    <!-- ... -->
</dx-data-grid>
Vue
App.vue
<template>
    <DxDataGrid>
        <DxMasterDetail
            :enabled="true"
            template="employee-info"
        />
        <template #employee-info="{ data: employee }">
            <div>
                <img class="employee-photo" :src="employee.data.Photo">
                <p class="employee-notes">{{ employee.data.Notes }}</p>
            </div>
        </template>
        <!-- ... -->
    </DxDataGrid>
</template>

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

</script>
React
App.tsx
import { DataGrid, MasterDetail } from 'devextreme-react/data-grid';

function DetailSection(props) {
    const employee = props.data.data;
    return (
        <div>
            <img
                className="employee-photo"
                alt={employee.FullName}
                src={employee.Photo}
            />
            <p className="employee-notes">{employee.Notes}</p>
        </div>
    );
}

function App() {
    return (
        <DataGrid>
            <MasterDetail
                enabled={true}
                component={DetailSection}
            />
            {/* ... */}
        </DataGrid>
    );
}

Export Data

DataGrid supports exporting data to Excel and PDF. Export functionality uses the following third-party libraries:

NOTE
To generate PDFs with Unicode characters, refer to the following troubleshooting guide: Export Unicode Characters - DataGrid.

To allow users to export data, set export.enabled to true and define an onExporting event handler. The component executes this handler when users click a button in the "exportButton" toolbar item. Call excelExporter.exportDataGrid(options) or pdfExporter.exportDataGrid(options) in this handler as follows:

jQuery
index.html
index.js
<html>
    <head>
        <!-- ... -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.4.0/polyfill.min.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/devextreme-exceljs-fork@4.4.1/dist/dx-exceljs-fork.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.2/FileSaver.min.js"></script>
        <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.3.1/jspdf.umd.min.js"></script>
        <!-- DevExtreme scripts are referenced here -->
        <!-- ... -->
    </head>
</html>
// This code is used for backwards compatibility with the older jsPDF variable name
// Read more: https://github.com/MrRio/jsPDF/releases/tag/v2.0.0
// window.jsPDF = window.jspdf.jsPDF;

$(function() {
    $("#dataGrid").dxDataGrid({
        export: {
            enabled: true,
            formats: ['xlsx', 'pdf']
        },
        onExporting(e) {
            if (e.format === 'xlsx') {
                const workbook = new ExcelJS.Workbook();
                const worksheet = workbook.addWorksheet('Main sheet');
                DevExpress.excelExporter.exportDataGrid({
                    worksheet,
                    component: e.component,
                }).then(() => {
                    workbook.xlsx.writeBuffer().then((buffer) => {
                        saveAs(new Blob([buffer], { type: 'application/octet-stream' }), 'DataGrid.xlsx');
                    });
                });
            } else if (e.format === 'pdf') {
                const doc = new window.jspdf.jsPDF();
                DevExpress.pdfExporter.exportDataGrid({
                    jsPDFDocument: doc,
                    component: e.component,
                }).then(() => {
                    doc.save('DataGrid.pdf');
                });
            }
        }
    });
});
ASP.NET Core Controls
Index.cshtml
@(Html.DevExtreme().DataGrid<Employee>()
    .Export(e => e
        .Enabled(true)
        .Formats(new[] { DataGridExportFormat.Pdf, DataGridExportFormat.Xlsx })
    )
    .OnExporting("handleDataGridExporting")
    @* ... *@
)

<script>
    function handleDataGridExporting(e) {
        if (e.format === 'xlsx') {
            const workbook = new ExcelJS.Workbook();
            const worksheet = workbook.addWorksheet('Main sheet');
            DevExpress.excelExporter.exportDataGrid({
                worksheet,
                component: e.component,
            }).then(() => {
                workbook.xlsx.writeBuffer().then((buffer) => {
                    saveAs(new Blob([buffer], { type: 'application/octet-stream' }), 'DataGrid.xlsx');
                });
            });
        } else if (e.format === 'pdf') {
            const doc = new window.jspdf.jsPDF();
            DevExpress.pdfExporter.exportDataGrid({
                jsPDFDocument: doc,
                component: e.component,
            }).then(() => {
                doc.save('DataGrid.pdf');
            });
        }
    }
</script>
Angular
Installation command
app.component.html
app.component.ts
npm install --save devextreme-exceljs-fork file-saver
npm install jspdf
<dx-data-grid (onExporting)="exportGrid($event)">
    <dxo-data-grid-export 
        [enabled]="true"
        [formats]="['xlsx', 'pdf']"
    ></dxo-data-grid-export>
    <!-- ... -->
</dx-data-grid>
import { type DxDataGridTypes } from 'devextreme-angular/ui/data-grid';
import { Workbook } from 'devextreme-exceljs-fork';
import saveAs from 'file-saver';
import { exportDataGrid } from 'devextreme/excel_exporter';
import { exportDataGrid as exportDataGridToPdf } from 'devextreme/pdf_exporter';
import { jsPDF } from 'jspdf';

// ...
export class AppComponent {
    exportGrid(e: DxDataGridTypes.ExportingEvent) {
        if (e.format === 'xlsx') {
            const workbook = new Workbook(); 
            const worksheet = workbook.addWorksheet("Main sheet"); 
            exportDataGrid({ 
                worksheet: worksheet, 
                component: e.component,
            }).then(function() {
                workbook.xlsx.writeBuffer().then(function(buffer) { 
                    saveAs(new Blob([buffer], { type: "application/octet-stream" }), "DataGrid.xlsx"); 
                }); 
            }); 
        } else if (e.format === 'pdf') {
            const doc = new jsPDF();
            exportDataGridToPdf({
                jsPDFDocument: doc,
                component: e.component,
            }).then(() => {
                doc.save('DataGrid.pdf');
            });
        }
    }
}
Vue
Installation command
App.vue
npm install --save devextreme-exceljs-fork file-saver
npm install jspdf
<template>
    <DxDataGrid @exporting="exportGrid">
        <!-- ... -->
        <DxExport
            :enabled="true"
            :formats="['xlsx', 'pdf']"
        />
    </DxDataGrid>
</template>

<script setup lang="ts">
import { DxDataGrid, DxExport, type DxDataGridTypes } from 'devextreme-vue/data-grid';
import { Workbook } from 'devextreme-exceljs-fork';
import { saveAs } from 'file-saver';
import { exportDataGrid } from 'devextreme/excel_exporter';
import { jsPDF } from 'jspdf';
import { exportDataGrid as exportDataGridToPdf} from 'devextreme/pdf_exporter';

function exportGrid(e: DxDataGridTypes.ExportingEvent): void {
    if (e.format === 'xlsx') {
        const workbook = new Workbook();
        const worksheet = workbook.addWorksheet('Main sheet');
        exportDataGrid({
            worksheet: worksheet,
            component: e.component,
        }).then(() => {
            workbook.xlsx.writeBuffer().then((buffer: ArrayBuffer) => {
                saveAs(new Blob([buffer], { type: 'application/octet-stream' }), 'DataGrid.xlsx');
            });
        });
    } else if (e.format === 'pdf') {
        const doc = new jsPDF();
        exportDataGridToPdf({
            jsPDFDocument: doc,
            component: e.component,
        }).then(() => {
            doc.save('DataGrid.pdf');
        });
    }
}
</script>
React
Installation command
App.tsx
npm install --save devextreme-exceljs-fork file-saver
npm install jspdf
import React, { useState } from 'react';

import { DataGrid, Export, type DataGridTypes } from 'devextreme-react/data-grid';

import { Workbook } from 'devextreme-exceljs-fork';
import saveAs from 'file-saver';
import { exportDataGrid } from 'devextreme/excel_exporter';
import { jsPDF } from 'jspdf';
import { exportDataGrid as exportDataGridToPdf} from 'devextreme/pdf_exporter';
// ...

const exportFormats = ['xlsx', 'pdf'];

function exportGrid(e: DataGridTypes.ExportingEvent) {
    if (e.format === 'xlsx') {
        const workbook = new Workbook(); 
        const worksheet = workbook.addWorksheet("Main sheet"); 
        exportDataGrid({ 
            worksheet: worksheet, 
            component: e.component,
        }).then(function() {
            workbook.xlsx.writeBuffer().then(function(buffer) { 
                saveAs(new Blob([buffer], { type: "application/octet-stream" }), "DataGrid.xlsx"); 
            }); 
        }); 
    } else if (e.format === 'pdf') {
        const doc = new jsPDF();
        exportDataGridToPdf({
            jsPDFDocument: doc,
            component: e.component,
        }).then(() => {
            doc.save('DataGrid.pdf');
        });
    }
}

function App() {
    return (
        <DataGrid onExporting={exportGrid}>
            <Export enabled={true} formats={exportFormats} />
            {/* ... */}
        </DataGrid>
    );
}

Export to Excel Overview Demo Export to PDF Overview Demo

NOTE
You can also export DataGrid to CSV. To do this, call the exportDataGrid(options) method in the same way as shown in the example of the DataGrid export.formats property. Refer to the CSV Injection section to take the threat of a CSV Injection Attack into account.

For more information about the DevExtreme DataGrid, refer to the following resources: