Getting Started with DataGrid

DataGrid is a widget that represents data from a local or remote source in the form of a grid.

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

Refer to the subtopics for details on each configuration step. You can also see the full code below or download it from the following GitHub repository: getting-started-with-datagrid

Create the DataGrid

jQuery

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

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/20.1.8/css/dx.common.css">
        <link rel="stylesheet" href="https://cdn3.devexpress.com/jslib/20.1.8/css/dx.light.css">
        <link rel="stylesheet" href="index.css">

        <script type="text/javascript" src="https://cdn3.devexpress.com/jslib/20.1.8/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;
}
Angular

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

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

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

App.vue
<template>
    <div id="app-container">
        <DxDataGrid id="dataGrid">
            <!-- Configuration goes here -->
        </DxDataGrid>
    </div>
</template>

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

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

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

<style>
#dataGrid {
    height: 500px;
}
</style>
React

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

App.js
App.css
import React from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.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

The DataGrid component can work with different data source types. To use a local array, assign it to the dataSource option and specify the key field in the keyExpr option to access data items, as we do in this tutorial. If you want to use another data source type, refer to one of the following articles:

jQuery
index.js
data.js
$(function() {
    $("#dataGrid").dxDataGrid({
        dataSource: employees,
        keyExpr: "EmployeeID",
    });
});
const employees = [{
    "EmployeeID": 1,
    "FullName": "Nancy Davolio",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1968-12-08T00:00:00.000Z",
    "HireDate": "2011-05-01T00:00:00.000Z",
    "Address": "507 - 20th Ave. E.\r\nApt. 2A",
    "City": "Seattle",
    "Region": "WA",
    "PostalCode": "98122",
    "Country": "USA",
    "HomePhone": "(206) 555-9857",
    "Extension": "5467",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/06.png",
    "Notes": "Education includes a BA in psychology from Colorado State University in 1990.  She also completed \"The Art of the Cold Call.\"  Nancy is a member of Toastmasters International.",
    "ReportsTo": 2
}, {
    "EmployeeID": 2,
    "FullName": "Andrew Fuller",
    "Position": "Vice President, Sales",
    "TitleOfCourtesy": "Dr.",
    "BirthDate": "1972-02-19T00:00:00.000Z",
    "HireDate": "2011-08-14T00:00:00.000Z",
    "Address": "908 W. Capital Way",
    "City": "Tacoma",
    "Region": "WA",
    "PostalCode": "98401",
    "Country": "USA",
    "HomePhone": "(206) 555-9482",
    "Extension": "3457",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/02.png",
    "Notes": "Andrew received his BTS commercial in 1994 and a Ph.D. in international marketing from the University of Dallas in 2001.  He is fluent in French and Italian and reads German.  He joined the company as a sales representative, was promoted to sales manager in January 2012 and to vice president of sales in March 2013.  Andrew is a member of the Sales Management Roundtable, the Seattle Chamber of Commerce, and the Pacific Rim Importers Association.",
    "ReportsTo": null
}, {
    "EmployeeID": 3,
    "FullName": "Janet Leverling",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1983-08-30T00:00:00.000Z",
    "HireDate": "2011-04-01T00:00:00.000Z",
    "Address": "722 Moss Bay Blvd.",
    "City": "Kirkland",
    "Region": "WA",
    "PostalCode": "98033",
    "Country": "USA",
    "HomePhone": "(206) 555-3412",
    "Extension": "3355",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/09.png",
    "Notes": "Janet has a BS degree in chemistry from Boston College (2004).  She has also completed a certificate program in food retailing management.  Janet was hired as a sales associate in 2011 and promoted to sales representative in February 2012.",
    "ReportsTo": 2
}, {
    "EmployeeID": 4,
    "FullName": "Margaret Peacock",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mrs.",
    "BirthDate": "1957-09-19T00:00:00.000Z",
    "HireDate": "2012-05-03T00:00:00.000Z",
    "Address": "4110 Old Redmond Rd.",
    "City": "Redmond",
    "Region": "WA",
    "PostalCode": "98052",
    "Country": "USA",
    "HomePhone": "(206) 555-8122",
    "Extension": "5176",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/04.png",
    "Notes": "Margaret holds a BA in English literature from Concordia College (1978) and an MA from the American Institute of Culinary Arts (1986).  She was assigned to the London office temporarily from July through November 2012.",
    "ReportsTo": 2
}, {
    "EmployeeID": 5,
    "FullName": "Steven Buchanan",
    "Position": "Sales Manager",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1975-03-04T00:00:00.000Z",
    "HireDate": "2012-10-17T00:00:00.000Z",
    "Address": "14 Garrett Hill",
    "City": "London",
    "Region": "UK",
    "PostalCode": "SW1 8JR",
    "Country": "UK",
    "HomePhone": "(71) 555-4848",
    "Extension": "3453",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/05.png",
    "Notes": "Steven Buchanan graduated from St. Andrews University, Scotland, with a BSC degree in 1996.  Upon joining the company as a sales representative in 2012, he spent 6 months in an orientation program at the Seattle office and then returned to his permanent post in London.  He was promoted to sales manager in March 2013.  Mr. Buchanan has completed the courses \"Successful Telemarketing\" and \"International Sales Management.\"  He is fluent in French.",
    "ReportsTo": 2
}, {
    "EmployeeID": 6,
    "FullName": "Michael Suyama",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1983-07-02T00:00:00.000Z",
    "HireDate": "2012-10-17T00:00:00.000Z",
    "Address": "Coventry House\r\nMiner Rd.",
    "City": "London",
    "Region": "UK",
    "PostalCode": "EC2 7JR",
    "Country": "UK",
    "HomePhone": "(71) 555-7773",
    "Extension": "428",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/01.png",
    "Notes": "Michael is a graduate of Sussex University (MA, economics, 2003) and the University of California at Los Angeles (MBA, marketing, 2006). He has also taken the courses \"Multi-Cultural Selling\" and \"Time Management for the Sales Professional.\"  He is fluent in Japanese and can read and write French, Portuguese, and Spanish.",
    "ReportsTo": 5
}, {
    "EmployeeID": 7,
    "FullName": "Robert King",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1980-05-29T00:00:00.000Z",
    "HireDate": "2012-01-02T00:00:00.000Z",
    "Address": "Edgeham Hollow\r\nWinchester Way",
    "City": "London",
    "Region": "UK",
    "PostalCode": "RG1 9SP",
    "Country": "UK",
    "HomePhone": "(71) 555-5598",
    "Extension": "465",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/07.png",
    "Notes": "Robert King served in the Peace Corps and traveled extensively before completing his degree in English at the University of Michigan in 2002, the year he joined the company.  After completing a course entitled \"Selling in Europe,\" he was transferred to the London office in March 2013.",
    "ReportsTo": 5
}, {
    "EmployeeID": 8,
    "FullName": "Laura Callahan",
    "Position": "Inside Sales Coordinator",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1978-01-09T00:00:00.000Z",
    "HireDate": "2012-03-05T00:00:00.000Z",
    "Address": "4726 - 11th Ave. N.E.",
    "City": "Seattle",
    "Region": "WA",
    "PostalCode": "98105",
    "Country": "USA",
    "HomePhone": "(206) 555-1189",
    "Extension": "2344",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/08.png",
    "Notes": "Laura received a BA in psychology from the University of Washington.  She has also completed a course in business French.  She reads and writes French.",
    "ReportsTo": 2
}, {
    "EmployeeID": 9,
    "FullName": "Brett Wade",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1986-01-27T00:00:00.000Z",
    "HireDate": "2012-11-15T00:00:00.000Z",
    "Address": "7 Houndstooth Rd.",
    "City": "London",
    "Region": "UK",
    "PostalCode": "WG2 7LT",
    "Country": "UK",
    "HomePhone": "(71) 555-4444",
    "Extension": "452",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/03.png",
    "Notes": "Brett has a BA degree in English from St. Lawrence College.  He is fluent in French and German.",
    "ReportsTo": 5
}];
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';

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
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
}

const employees: Employee[] = [{
    "EmployeeID": 1,
    "FullName": "Nancy Davolio",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1968-12-08T00:00:00.000Z",
    "HireDate": "2011-05-01T00:00:00.000Z",
    "Address": "507 - 20th Ave. E.\r\nApt. 2A",
    "City": "Seattle",
    "Region": "WA",
    "PostalCode": "98122",
    "Country": "USA",
    "HomePhone": "(206) 555-9857",
    "Extension": "5467",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/06.png",
    "Notes": "Education includes a BA in psychology from Colorado State University in 1990.  She also completed \"The Art of the Cold Call.\"  Nancy is a member of Toastmasters International.",
    "ReportsTo": 2
}, {
    "EmployeeID": 2,
    "FullName": "Andrew Fuller",
    "Position": "Vice President, Sales",
    "TitleOfCourtesy": "Dr.",
    "BirthDate": "1972-02-19T00:00:00.000Z",
    "HireDate": "2011-08-14T00:00:00.000Z",
    "Address": "908 W. Capital Way",
    "City": "Tacoma",
    "Region": "WA",
    "PostalCode": "98401",
    "Country": "USA",
    "HomePhone": "(206) 555-9482",
    "Extension": "3457",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/02.png",
    "Notes": "Andrew received his BTS commercial in 1994 and a Ph.D. in international marketing from the University of Dallas in 2001.  He is fluent in French and Italian and reads German.  He joined the company as a sales representative, was promoted to sales manager in January 2012 and to vice president of sales in March 2013.  Andrew is a member of the Sales Management Roundtable, the Seattle Chamber of Commerce, and the Pacific Rim Importers Association.",
    "ReportsTo": null
}, {
    "EmployeeID": 3,
    "FullName": "Janet Leverling",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1983-08-30T00:00:00.000Z",
    "HireDate": "2011-04-01T00:00:00.000Z",
    "Address": "722 Moss Bay Blvd.",
    "City": "Kirkland",
    "Region": "WA",
    "PostalCode": "98033",
    "Country": "USA",
    "HomePhone": "(206) 555-3412",
    "Extension": "3355",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/09.png",
    "Notes": "Janet has a BS degree in chemistry from Boston College (2004).  She has also completed a certificate program in food retailing management.  Janet was hired as a sales associate in 2011 and promoted to sales representative in February 2012.",
    "ReportsTo": 2
}, {
    "EmployeeID": 4,
    "FullName": "Margaret Peacock",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mrs.",
    "BirthDate": "1957-09-19T00:00:00.000Z",
    "HireDate": "2012-05-03T00:00:00.000Z",
    "Address": "4110 Old Redmond Rd.",
    "City": "Redmond",
    "Region": "WA",
    "PostalCode": "98052",
    "Country": "USA",
    "HomePhone": "(206) 555-8122",
    "Extension": "5176",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/04.png",
    "Notes": "Margaret holds a BA in English literature from Concordia College (1978) and an MA from the American Institute of Culinary Arts (1986).  She was assigned to the London office temporarily from July through November 2012.",
    "ReportsTo": 2
}, {
    "EmployeeID": 5,
    "FullName": "Steven Buchanan",
    "Position": "Sales Manager",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1975-03-04T00:00:00.000Z",
    "HireDate": "2012-10-17T00:00:00.000Z",
    "Address": "14 Garrett Hill",
    "City": "London",
    "Region": "UK",
    "PostalCode": "SW1 8JR",
    "Country": "UK",
    "HomePhone": "(71) 555-4848",
    "Extension": "3453",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/05.png",
    "Notes": "Steven Buchanan graduated from St. Andrews University, Scotland, with a BSC degree in 1996.  Upon joining the company as a sales representative in 2012, he spent 6 months in an orientation program at the Seattle office and then returned to his permanent post in London.  He was promoted to sales manager in March 2013.  Mr. Buchanan has completed the courses \"Successful Telemarketing\" and \"International Sales Management.\"  He is fluent in French.",
    "ReportsTo": 2
}, {
    "EmployeeID": 6,
    "FullName": "Michael Suyama",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1983-07-02T00:00:00.000Z",
    "HireDate": "2012-10-17T00:00:00.000Z",
    "Address": "Coventry House\r\nMiner Rd.",
    "City": "London",
    "Region": "UK",
    "PostalCode": "EC2 7JR",
    "Country": "UK",
    "HomePhone": "(71) 555-7773",
    "Extension": "428",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/01.png",
    "Notes": "Michael is a graduate of Sussex University (MA, economics, 2003) and the University of California at Los Angeles (MBA, marketing, 2006). He has also taken the courses \"Multi-Cultural Selling\" and \"Time Management for the Sales Professional.\"  He is fluent in Japanese and can read and write French, Portuguese, and Spanish.",
    "ReportsTo": 5
}, {
    "EmployeeID": 7,
    "FullName": "Robert King",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1980-05-29T00:00:00.000Z",
    "HireDate": "2012-01-02T00:00:00.000Z",
    "Address": "Edgeham Hollow\r\nWinchester Way",
    "City": "London",
    "Region": "UK",
    "PostalCode": "RG1 9SP",
    "Country": "UK",
    "HomePhone": "(71) 555-5598",
    "Extension": "465",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/07.png",
    "Notes": "Robert King served in the Peace Corps and traveled extensively before completing his degree in English at the University of Michigan in 2002, the year he joined the company.  After completing a course entitled \"Selling in Europe,\" he was transferred to the London office in March 2013.",
    "ReportsTo": 5
}, {
    "EmployeeID": 8,
    "FullName": "Laura Callahan",
    "Position": "Inside Sales Coordinator",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1978-01-09T00:00:00.000Z",
    "HireDate": "2012-03-05T00:00:00.000Z",
    "Address": "4726 - 11th Ave. N.E.",
    "City": "Seattle",
    "Region": "WA",
    "PostalCode": "98105",
    "Country": "USA",
    "HomePhone": "(206) 555-1189",
    "Extension": "2344",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/08.png",
    "Notes": "Laura received a BA in psychology from the University of Washington.  She has also completed a course in business French.  She reads and writes French.",
    "ReportsTo": 2
}, {
    "EmployeeID": 9,
    "FullName": "Brett Wade",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1986-01-27T00:00:00.000Z",
    "HireDate": "2012-11-15T00:00:00.000Z",
    "Address": "7 Houndstooth Rd.",
    "City": "London",
    "Region": "UK",
    "PostalCode": "WG2 7LT",
    "Country": "UK",
    "HomePhone": "(71) 555-4444",
    "Extension": "452",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/03.png",
    "Notes": "Brett has a BA degree in English from St. Lawrence College.  He is fluent in French and German.",
    "ReportsTo": 5
}];

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

<script>
// ...
import service from './employees.service';

export default {
    // ...
    data() {
        return {
            employees: service.getEmployees(),
        }
    },
}
</script>
const employees = [{
    "EmployeeID": 1,
    "FullName": "Nancy Davolio",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1968-12-08T00:00:00.000Z",
    "HireDate": "2011-05-01T00:00:00.000Z",
    "Address": "507 - 20th Ave. E.\r\nApt. 2A",
    "City": "Seattle",
    "Region": "WA",
    "PostalCode": "98122",
    "Country": "USA",
    "HomePhone": "(206) 555-9857",
    "Extension": "5467",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/06.png",
    "Notes": "Education includes a BA in psychology from Colorado State University in 1990.  She also completed \"The Art of the Cold Call.\"  Nancy is a member of Toastmasters International.",
    "ReportsTo": 2
}, {
    "EmployeeID": 2,
    "FullName": "Andrew Fuller",
    "Position": "Vice President, Sales",
    "TitleOfCourtesy": "Dr.",
    "BirthDate": "1972-02-19T00:00:00.000Z",
    "HireDate": "2011-08-14T00:00:00.000Z",
    "Address": "908 W. Capital Way",
    "City": "Tacoma",
    "Region": "WA",
    "PostalCode": "98401",
    "Country": "USA",
    "HomePhone": "(206) 555-9482",
    "Extension": "3457",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/02.png",
    "Notes": "Andrew received his BTS commercial in 1994 and a Ph.D. in international marketing from the University of Dallas in 2001.  He is fluent in French and Italian and reads German.  He joined the company as a sales representative, was promoted to sales manager in January 2012 and to vice president of sales in March 2013.  Andrew is a member of the Sales Management Roundtable, the Seattle Chamber of Commerce, and the Pacific Rim Importers Association.",
    "ReportsTo": null
}, {
    "EmployeeID": 3,
    "FullName": "Janet Leverling",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1983-08-30T00:00:00.000Z",
    "HireDate": "2011-04-01T00:00:00.000Z",
    "Address": "722 Moss Bay Blvd.",
    "City": "Kirkland",
    "Region": "WA",
    "PostalCode": "98033",
    "Country": "USA",
    "HomePhone": "(206) 555-3412",
    "Extension": "3355",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/09.png",
    "Notes": "Janet has a BS degree in chemistry from Boston College (2004).  She has also completed a certificate program in food retailing management.  Janet was hired as a sales associate in 2011 and promoted to sales representative in February 2012.",
    "ReportsTo": 2
}, {
    "EmployeeID": 4,
    "FullName": "Margaret Peacock",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mrs.",
    "BirthDate": "1957-09-19T00:00:00.000Z",
    "HireDate": "2012-05-03T00:00:00.000Z",
    "Address": "4110 Old Redmond Rd.",
    "City": "Redmond",
    "Region": "WA",
    "PostalCode": "98052",
    "Country": "USA",
    "HomePhone": "(206) 555-8122",
    "Extension": "5176",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/04.png",
    "Notes": "Margaret holds a BA in English literature from Concordia College (1978) and an MA from the American Institute of Culinary Arts (1986).  She was assigned to the London office temporarily from July through November 2012.",
    "ReportsTo": 2
}, {
    "EmployeeID": 5,
    "FullName": "Steven Buchanan",
    "Position": "Sales Manager",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1975-03-04T00:00:00.000Z",
    "HireDate": "2012-10-17T00:00:00.000Z",
    "Address": "14 Garrett Hill",
    "City": "London",
    "Region": "UK",
    "PostalCode": "SW1 8JR",
    "Country": "UK",
    "HomePhone": "(71) 555-4848",
    "Extension": "3453",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/05.png",
    "Notes": "Steven Buchanan graduated from St. Andrews University, Scotland, with a BSC degree in 1996.  Upon joining the company as a sales representative in 2012, he spent 6 months in an orientation program at the Seattle office and then returned to his permanent post in London.  He was promoted to sales manager in March 2013.  Mr. Buchanan has completed the courses \"Successful Telemarketing\" and \"International Sales Management.\"  He is fluent in French.",
    "ReportsTo": 2
}, {
    "EmployeeID": 6,
    "FullName": "Michael Suyama",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1983-07-02T00:00:00.000Z",
    "HireDate": "2012-10-17T00:00:00.000Z",
    "Address": "Coventry House\r\nMiner Rd.",
    "City": "London",
    "Region": "UK",
    "PostalCode": "EC2 7JR",
    "Country": "UK",
    "HomePhone": "(71) 555-7773",
    "Extension": "428",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/01.png",
    "Notes": "Michael is a graduate of Sussex University (MA, economics, 2003) and the University of California at Los Angeles (MBA, marketing, 2006). He has also taken the courses \"Multi-Cultural Selling\" and \"Time Management for the Sales Professional.\"  He is fluent in Japanese and can read and write French, Portuguese, and Spanish.",
    "ReportsTo": 5
}, {
    "EmployeeID": 7,
    "FullName": "Robert King",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1980-05-29T00:00:00.000Z",
    "HireDate": "2012-01-02T00:00:00.000Z",
    "Address": "Edgeham Hollow\r\nWinchester Way",
    "City": "London",
    "Region": "UK",
    "PostalCode": "RG1 9SP",
    "Country": "UK",
    "HomePhone": "(71) 555-5598",
    "Extension": "465",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/07.png",
    "Notes": "Robert King served in the Peace Corps and traveled extensively before completing his degree in English at the University of Michigan in 2002, the year he joined the company.  After completing a course entitled \"Selling in Europe,\" he was transferred to the London office in March 2013.",
    "ReportsTo": 5
}, {
    "EmployeeID": 8,
    "FullName": "Laura Callahan",
    "Position": "Inside Sales Coordinator",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1978-01-09T00:00:00.000Z",
    "HireDate": "2012-03-05T00:00:00.000Z",
    "Address": "4726 - 11th Ave. N.E.",
    "City": "Seattle",
    "Region": "WA",
    "PostalCode": "98105",
    "Country": "USA",
    "HomePhone": "(206) 555-1189",
    "Extension": "2344",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/08.png",
    "Notes": "Laura received a BA in psychology from the University of Washington.  She has also completed a course in business French.  She reads and writes French.",
    "ReportsTo": 2
}, {
    "EmployeeID": 9,
    "FullName": "Brett Wade",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1986-01-27T00:00:00.000Z",
    "HireDate": "2012-11-15T00:00:00.000Z",
    "Address": "7 Houndstooth Rd.",
    "City": "London",
    "Region": "UK",
    "PostalCode": "WG2 7LT",
    "Country": "UK",
    "HomePhone": "(71) 555-4444",
    "Extension": "452",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/03.png",
    "Notes": "Brett has a BA degree in English from St. Lawrence College.  He is fluent in French and German.",
    "ReportsTo": 5
}];

export default {
    getEmployees() {
        return employees;
    }
}
React
App.js
employees.js
import React from 'react';

import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

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

function App() {
    return (
        <div className="App">
            <DataGrid
                dataSource={employees}
                keyExpr="EmployeeID">
            </DataGrid>
        </div>
    );
}

export default App;
export const employees = [{
    "EmployeeID": 1,
    "FullName": "Nancy Davolio",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1968-12-08T00:00:00.000Z",
    "HireDate": "2011-05-01T00:00:00.000Z",
    "Address": "507 - 20th Ave. E.\r\nApt. 2A",
    "City": "Seattle",
    "Region": "WA",
    "PostalCode": "98122",
    "Country": "USA",
    "HomePhone": "(206) 555-9857",
    "Extension": "5467",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/06.png",
    "Notes": "Education includes a BA in psychology from Colorado State University in 1990.  She also completed \"The Art of the Cold Call.\"  Nancy is a member of Toastmasters International.",
    "ReportsTo": 2
}, {
    "EmployeeID": 2,
    "FullName": "Andrew Fuller",
    "Position": "Vice President, Sales",
    "TitleOfCourtesy": "Dr.",
    "BirthDate": "1972-02-19T00:00:00.000Z",
    "HireDate": "2011-08-14T00:00:00.000Z",
    "Address": "908 W. Capital Way",
    "City": "Tacoma",
    "Region": "WA",
    "PostalCode": "98401",
    "Country": "USA",
    "HomePhone": "(206) 555-9482",
    "Extension": "3457",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/02.png",
    "Notes": "Andrew received his BTS commercial in 1994 and a Ph.D. in international marketing from the University of Dallas in 2001.  He is fluent in French and Italian and reads German.  He joined the company as a sales representative, was promoted to sales manager in January 2012 and to vice president of sales in March 2013.  Andrew is a member of the Sales Management Roundtable, the Seattle Chamber of Commerce, and the Pacific Rim Importers Association.",
    "ReportsTo": null
}, {
    "EmployeeID": 3,
    "FullName": "Janet Leverling",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1983-08-30T00:00:00.000Z",
    "HireDate": "2011-04-01T00:00:00.000Z",
    "Address": "722 Moss Bay Blvd.",
    "City": "Kirkland",
    "Region": "WA",
    "PostalCode": "98033",
    "Country": "USA",
    "HomePhone": "(206) 555-3412",
    "Extension": "3355",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/09.png",
    "Notes": "Janet has a BS degree in chemistry from Boston College (2004).  She has also completed a certificate program in food retailing management.  Janet was hired as a sales associate in 2011 and promoted to sales representative in February 2012.",
    "ReportsTo": 2
}, {
    "EmployeeID": 4,
    "FullName": "Margaret Peacock",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mrs.",
    "BirthDate": "1957-09-19T00:00:00.000Z",
    "HireDate": "2012-05-03T00:00:00.000Z",
    "Address": "4110 Old Redmond Rd.",
    "City": "Redmond",
    "Region": "WA",
    "PostalCode": "98052",
    "Country": "USA",
    "HomePhone": "(206) 555-8122",
    "Extension": "5176",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/04.png",
    "Notes": "Margaret holds a BA in English literature from Concordia College (1978) and an MA from the American Institute of Culinary Arts (1986).  She was assigned to the London office temporarily from July through November 2012.",
    "ReportsTo": 2
}, {
    "EmployeeID": 5,
    "FullName": "Steven Buchanan",
    "Position": "Sales Manager",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1975-03-04T00:00:00.000Z",
    "HireDate": "2012-10-17T00:00:00.000Z",
    "Address": "14 Garrett Hill",
    "City": "London",
    "Region": "UK",
    "PostalCode": "SW1 8JR",
    "Country": "UK",
    "HomePhone": "(71) 555-4848",
    "Extension": "3453",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/05.png",
    "Notes": "Steven Buchanan graduated from St. Andrews University, Scotland, with a BSC degree in 1996.  Upon joining the company as a sales representative in 2012, he spent 6 months in an orientation program at the Seattle office and then returned to his permanent post in London.  He was promoted to sales manager in March 2013.  Mr. Buchanan has completed the courses \"Successful Telemarketing\" and \"International Sales Management.\"  He is fluent in French.",
    "ReportsTo": 2
}, {
    "EmployeeID": 6,
    "FullName": "Michael Suyama",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1983-07-02T00:00:00.000Z",
    "HireDate": "2012-10-17T00:00:00.000Z",
    "Address": "Coventry House\r\nMiner Rd.",
    "City": "London",
    "Region": "UK",
    "PostalCode": "EC2 7JR",
    "Country": "UK",
    "HomePhone": "(71) 555-7773",
    "Extension": "428",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/01.png",
    "Notes": "Michael is a graduate of Sussex University (MA, economics, 2003) and the University of California at Los Angeles (MBA, marketing, 2006). He has also taken the courses \"Multi-Cultural Selling\" and \"Time Management for the Sales Professional.\"  He is fluent in Japanese and can read and write French, Portuguese, and Spanish.",
    "ReportsTo": 5
}, {
    "EmployeeID": 7,
    "FullName": "Robert King",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1980-05-29T00:00:00.000Z",
    "HireDate": "2012-01-02T00:00:00.000Z",
    "Address": "Edgeham Hollow\r\nWinchester Way",
    "City": "London",
    "Region": "UK",
    "PostalCode": "RG1 9SP",
    "Country": "UK",
    "HomePhone": "(71) 555-5598",
    "Extension": "465",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/07.png",
    "Notes": "Robert King served in the Peace Corps and traveled extensively before completing his degree in English at the University of Michigan in 2002, the year he joined the company.  After completing a course entitled \"Selling in Europe,\" he was transferred to the London office in March 2013.",
    "ReportsTo": 5
}, {
    "EmployeeID": 8,
    "FullName": "Laura Callahan",
    "Position": "Inside Sales Coordinator",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1978-01-09T00:00:00.000Z",
    "HireDate": "2012-03-05T00:00:00.000Z",
    "Address": "4726 - 11th Ave. N.E.",
    "City": "Seattle",
    "Region": "WA",
    "PostalCode": "98105",
    "Country": "USA",
    "HomePhone": "(206) 555-1189",
    "Extension": "2344",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/08.png",
    "Notes": "Laura received a BA in psychology from the University of Washington.  She has also completed a course in business French.  She reads and writes French.",
    "ReportsTo": 2
}, {
    "EmployeeID": 9,
    "FullName": "Brett Wade",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Mr.",
    "BirthDate": "1986-01-27T00:00:00.000Z",
    "HireDate": "2012-11-15T00:00:00.000Z",
    "Address": "7 Houndstooth Rd.",
    "City": "London",
    "Region": "UK",
    "PostalCode": "WG2 7LT",
    "Country": "UK",
    "HomePhone": "(71) 555-4444",
    "Extension": "452",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/03.png",
    "Notes": "Brett has a BA degree in English from St. Lawrence College.  He is fluent in French and German.",
    "ReportsTo": 5
}];

If you run this code, you should see a DataGrid in which a column is created for each data field. All the columns have an equal width and the same order as their data fields. In the next step, we will resize, reorder, and hide some of the columns.

Customize Columns

To customize grid columns, declare the columns array. This array can contain objects (column configurations) or text strings (data field names). Text strings can be used if you do not need to specify any column options except the dataField.

Reorder Columns

To reorder grid columns, change their order in the columns array. Users also can reorder columns if you enable the allowColumnReordering option.

jQuery
index.js
$(function() {
    $("#dataGrid").dxDataGrid({
        // ...
        columns: [{
            dataField: "FullName"
        }, {
            dataField: "Position"
        }, {
            dataField: "BirthDate", 
            dataType: "date",
        }, {
            dataField: "HireDate", 
            dataType: "date",
        },"City", {
            dataField: "Country"
        },
        "Address",
        "HomePhone",
        {
            dataField: "PostalCode",
        }],
        allowColumnReordering: true,
    });
});
Angular
app.component.html
<dx-data-grid ...
    [allowColumnReordering]="true">
    <dxi-column dataField="FullName"></dxi-column>
    <dxi-column dataField="Position"></dxi-column>
    <dxi-column
        dataField="BirthDate"
        dataType="date">
    </dxi-column>
    <dxi-column
        dataField="HireDate"
        dataType="date">
    </dxi-column>
    <dxi-column dataField="City"></dxi-column>
    <dxi-column dataField="Country"></dxi-column>
    <dxi-column dataField="Address"></dxi-column>
    <dxi-column dataField="HomePhone"></dxi-column>
    <dxi-column dataField="PostalCode"></dxi-column>
</dx-data-grid>
Vue
App.vue
<template>
    <div id="app-container">
        <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>
    </div>
</template>

<script>
// ...
import {
    DxDataGrid,
    DxColumn
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        DxColumn
    },
    // ...
}
</script>
React
App.js
import React from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

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

function App() {
    return (
        <div className="App">
            <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>
        </div>
    );
}

export default App;

In the code above, we also specify the "date" dataType for the BirthDate and HireDate columns. This is needed because the DataGrid detects data types automatically based on column values, and BirthDate and HireDate values are stored in the data source as strings.

Resize Columns

Grid columns have equal widths by default. You can set a width for individual columns or specify that all columns should adjust their widths to their contents (columnAutoWidth). Users can resize columns if you enable the allowColumnResizing option.

jQuery
index.js
$(function() {
    $("#dataGrid").dxDataGrid({
        // ...
        columns: [
        // ...
        {
            dataField: "BirthDate", 
            dataType: "date",
            width: 100,
        }, {
            dataField: "HireDate", 
            dataType: "date",
            width: 100,
        },
        // ...
        ],
        allowColumnResizing: true,
        columnAutoWidth: true,
    });
});
Angular
app.component.html
<dx-data-grid ...
    [allowColumnResizing]="true"
    [columnAutoWidth]="true">
    <!-- ... -->
    <dxi-column
        dataField="BirthDate"
        dataType="date"
        [width]="100">
    </dxi-column>
    <dxi-column
        dataField="HireDate"
        dataType="date"
        [width]="100">
    </dxi-column>
    <!-- ... -->
</dx-data-grid>
Vue
App.vue
<template>
    <div id="app-container">
        <DxDataGrid ...
            :allow-column-reordering="true"
            :column-auto-width="true">
            <!-- ... -->
            <DxColumn
                data-field="BirthDate"
                data-type="date"
                :width="100">
            </DxColumn>
            <DxColumn
                data-field="HireDate"
                data-type="date"
                :width="100">
            </DxColumn>
            <!-- ... -->
        </DxDataGrid>
    </div>
</template>

<script>
import {
    DxDataGrid,
    DxColumn
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        DxColumn
    },
    // ...
}
</script>
React
App.js
import React from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

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

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

export default App;

Fix Columns

When the width of all columns exceeds the widget width, horizontal scrolling appears. If specific columns should be on screen constantly regardless of how far the widget is scrolled, allow a user to fix them at runtime using the context menu. For this, set the columnFixing.enabled option to true.

You can also fix a column in code by enabling its fixed option. The column is fixed to the widget's left edge by default. To change the position, set the fixedPosition option.

In the following code, we fix the FullName column to the default left position and allow users to fix and unfix columns at runtime:

jQuery
index.js
$(function() {
    $("#dataGrid").dxDataGrid({
        // ...
        columnFixing: { enabled: true },
        columns: [{
            dataField: "FullName", 
            fixed: true
        },
        // ...
        ],
        // ...
    });
});
Angular
app.component.html
<dx-data-grid ... >
    <dxi-column
        dataField="FullName"
        [fixed]="true">
    </dxi-column>
    <!-- ... -->
    <dxo-column-fixing [enabled]="true"></dxo-column-fixing>
</dx-data-grid>
Vue
App.vue
<template>
    <div id="app-container">
        <DxDataGrid ... >
            <DxColumn
                data-field="FullName"
                :fixed="true">
            </DxColumn>
            <!-- ... -->
            <DxColumnFixing :enabled="true" />
        </DxDataGrid>
    </div>
</template>

<script>
import {
    DxDataGrid,
    DxColumn,
    DxColumnFixing
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        DxColumn,
        DxColumnFixing
    },
    // ...
}
</script>
React
App.js
import React from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

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

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

export default App;

Hide Columns

The DataGrid displays all columns from the columns array. To hide a column, set its visible option to false. Hidden columns appear in the columnChooser. Users can restore hidden columns from it. To enable the column chooser. set the columnChooser.enabled option to true. If a column should not be visible even in the column chooser, simply do not declare it in the columns array.

jQuery
index.js
$(function() {
    $("#dataGrid").dxDataGrid({
        // ...
        columns: [
        // ...
        {
            dataField: "PostalCode",
            visible: false
        }],
        columnChooser: { enabled: true },
    });
});
Angular
app.component.html
<dx-data-grid ... >
    <!-- ... -->
    <dxi-column dataField="PostalCode" [visible]="false"></dxi-column>
    <dxo-column-chooser [enabled]="true"></dxo-column-chooser>
</dx-data-grid>
Vue
App.vue
<template>
    <div id="app-container">
        <DxDataGrid ... >
            <!-- ... -->
            <DxColumn data-field="PostalCode" :visible="false" />
            <DxColumnChooser :enabled="true" />
        </DxDataGrid>
    </div>
</template>

<script>
import {
    DxDataGrid,
    DxColumn,
    DxColumnChooser
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        DxColumn,
        DxColumnChooser
    },
    // ...
}
</script>
React
App.js
import React from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

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

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

export default App;

The next step describes how to sort data in code and in the UI.

Sort Data

Users can sort grid records by a single or multiple columns. Use the sorting.mode option to set the mode. This tutorial uses the default sorting mode - single.

You can also set a column's sortOrder and sortIndex options to specify initial sorting settings. sortIndex applies only in multiple sorting mode.

jQuery
index.js
$(function() {
    $("#dataGrid").dxDataGrid({
        // ...
        columns: [{
            dataField: "Country",
            sortOrder: "asc",
        },
        // ...
        ],
        // sorting: { mode: "single" },
    });
});
Angular
app.component.html
<dx-data-grid ... >
    <!-- ... -->
    <dxi-column
        dataField="Country"
        sortOrder="asc">
    </dxi-column>
    <!-- <dxo-sorting [mode]="single"></dxo-sorting> -->
</dx-data-grid>
Vue
App.vue
<template>
    <div id="app-container">
        <DxDataGrid ... >
            <!-- ... -->
            <DxColumn
                data-field="Country"
                sort-order="asc">
            </DxColumn>
            <!-- <DxSorting mode="single" /> -->
        </DxDataGrid>
    </div>
</template>

<script>
import {
    DxDataGrid,
    DxColumn,
    // ...
    // DxSorting
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        DxColumn,
        // ...
        // DxSorting
    },
    // ...
}
</script>
React
App.js
import React from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import {
    DataGrid,
    Column,
    // ...
    // Sorting
} from 'devextreme-react/data-grid';

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

export default App;

Run the code and ensure that grid records are sorted by the Country column. Click a column header to sort the records by another column. Next, we will configure filtering and searching.

Filter and Search Data

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

In this tutorial, we display the filterRow and searchPanel:

jQuery
index.js
$(function() {
    $("#dataGrid").dxDataGrid({
        // ...
        filterRow: { visible: true },
        searchPanel: { visible: true },
    });
});
Angular
app.component.html
<dx-data-grid ... >
    <!-- ... -->
    <dxo-filter-row [visible]="true"></dxo-filter-row>
    <dxo-search-panel [visible]="true"></dxo-search-panel>
</dx-data-grid>
Vue
App.vue
<template>
    <div id="app-container">
        <DxDataGrid ... >
            <!-- ... -->
            <DxFilterRow :visible="true" />
            <DxSearchPanel :visible="true" />
        </DxDataGrid>
    </div>
</template>

<script>
import {
    DxDataGrid,
    // ...
    DxFilterRow,
    DxSearchPanel
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        // ...
        DxFilterRow,
        DxSearchPanel
    },
    // ...
}
</script>
React
App.js
import React from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import {
    DataGrid,
    // ...
    FilterRow,
    SearchPanel
} from 'devextreme-react/data-grid';

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

export default App;

Run the code and enter a value into a filter row cell or the search panel. Grid data will be filtered according to this value. In the next step, we will configure grouping.

Group Data

Grid records can be grouped by values of one or multiple columns. To group records, users should drag and drop column headers onto the groupPanel. Enable the groupPanel.visible option to display this UI element.

You can also group records programmatically. Specify the groupIndex option for the columns by which records should be grouped. In this tutorial, the groupIndex is specified for the Country column:

jQuery
index.js
$(function() {
    $("#dataGrid").dxDataGrid({
        columns: [
        // ...
        {
            dataField: "Country",
            // ...
            groupIndex: 0,
        },
        // ...
        ],
        groupPanel: { visible: true },
    });
});
Angular
app.component.html
<dx-data-grid ... >
    <!-- ... -->
    <dxi-column
        dataField="Country"
        ...
        [groupIndex]="0">
    </dxi-column>
    <dxo-group-panel [visible]="true"></dxo-group-panel>
</dx-data-grid>
Vue
App.vue
<template>
    <div id="app-container">
        <DxDataGrid ... >
            <!-- ... -->
            <DxColumn
                data-field="Country"
                ...
                :group-index="0">
            </DxColumn>
            <DxGroupPanel :visible="true" />
        </DxDataGrid>
    </div>
</template>

<script>
import {
    DxDataGrid,
    DxColumn,
    // ...
    DxGroupPanel
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        DxColumn,
        // ...
        DxGroupPanel
    },
    // ...
}
</script>
React
App.js
import React from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import {
    DataGrid,
    Column,
    // ...
    GroupPanel
} from 'devextreme-react/data-grid';

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

export default App;

If you run the code, you should see that records are grouped by the Country column. This column's header is on the group panel. Drag and drop column headers to and from the group panel to change the grouping.

In the next step, we will configure data validation and allow users to edit data.

Edit and Validate Data

Users can add new records and update or delete existing records. To allow each of these operations, enable the allowAdding, allowUpdating, and allowDeleting options in the editing object. The DataGrid also supports multiple edit modes. This tutorial uses the popup edit mode.

DevExtreme includes a validation engine that validates edited values before they are saved. This engine supports different validation rule types, such as Email, Compare, Range, and more. Validation rules are specified per column; one column can have multiple rules. In this tutorial, several columns have the Required rule.

jQuery
index.js
$(function() {
    $("#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" }]
        },
        // ...
        ],
    });
});
Angular
app.component.html
<dx-data-grid ... >
    <!-- ... -->
    <dxi-column dataField="FullName">
        <dxi-validation-rule type="required"></dxi-validation-rule>
    </dxi-column>
    <dxi-column dataField="Position">
        <dxi-validation-rule type="required"></dxi-validation-rule>
    </dxi-column>
    <dxi-column ...
        dataField="BirthDate">
        <dxi-validation-rule type="required"></dxi-validation-rule>
    </dxi-column>
    <dxi-column ...
        dataField="HireDate">
        <dxi-validation-rule type="required"></dxi-validation-rule>
    </dxi-column>
    <dxi-column ...
        dataField="Country">
        <dxi-validation-rule type="required"></dxi-validation-rule>
    </dxi-column>
    <dxo-editing
        mode="popup"
        [allowUpdating]="true"
        [allowDeleting]="true"
        [allowAdding]="true">
    </dxo-editing>
</dx-data-grid>
Vue
App.vue
<template>
    <div id="app-container">
        <DxDataGrid ... >
            <!-- ... -->
            <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>
            <DxEditing
                mode="popup"
                :allow-updating="true"
                :allow-adding="true"
                :allow-deleting="true"
            />
        </DxDataGrid>
    </div>
</template>

<script>
import {
    DxDataGrid,
    DxColumn,
    // ...
    DxRequiredRule,
    DxEditing
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        DxColumn,
        // ...
        DxRequiredRule,
        DxEditing
    },
    // ...
}
</script>
React
App.js
import React from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';

import {
    DataGrid,
    Column,
    // ...
    RequiredRule,
    Editing
} from 'devextreme-react/data-grid';

function App() {
    return (
        <div className="App">
            <DataGrid ... >
                {/* ... */}
                <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>
                <Editing
                    mode="popup"
                    allowUpdating={true}
                    allowDeleting={true}
                    allowAdding={true}
                />
            </DataGrid>
        </div>
    );
}

export default App;

Run the code and click the Edit button in any row. You will see a popup window that contains an edit form. Clear the Full Name text box on this form. You should see the following validation error: "First Name is required".

In the following step, we will configure record selection.

Select Records

The DataGrid supports single and multiple record selection modes. To specify the mode, set the selection.mode option.

You can access the selected record's data in the onSelectionChanged function. In the code below, this function displays the selected employee under the DataGrid:

jQuery
index.js
index.html
index.css
$(function() {
    $("#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>
/* ... */
#app-container {
    width: 900px;
    position: relative;
}

#selected-employee {
    position: absolute;
    left: 50%;
    transform: translate(-50%, 0);
}
Angular
app.component.html
app.component.ts
app.component.css
<div id="app-container">
    <dx-data-grid ...
        (onSelectionChanged)="selectEmployee($event)">
        <!-- ... -->
        <dxo-selection mode="single"></dxo-selection>
    </dx-data-grid>
    <p id="selected-employee" *ngIf="selectedEmployee">
        Selected employee: {{ selectedEmployee.FullName }}
    </p>
</div>
import { Component } from '@angular/core';
import { Employee, EmployeesService } from './employees.service';

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

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

    selectEmployee(e) {
        e.component.byKey(e.currentSelectedRowKeys[0]).done(employee => {
            if(employee) {
                this.selectedEmployee = employee;
            }
        });
    }
}
/* ... */
#app-container {
    width: 900px;
    position: relative;
}

#selected-employee {
    position: absolute;
    left: 50%;
    transform: translate(-50%, 0);
}
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>
import {
    DxDataGrid,
    // ...
    DxSelection
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        // ...
        DxSelection
    },
    data() {
        return {
            // ...
            selectedEmployee: undefined,
        }
    },
    methods: {
        selectEmployee(e) {
            e.component.byKey(e.currentSelectedRowKeys[0]).done(employee => {
                if(employee) {
                    this.selectedEmployee = employee;
                }
            });
        }
    }
}
</script>

<style>
/* ... */
#app-container {
    width: 900px;
    position: relative;
}

#selected-employee {
    position: absolute;
    left: 50%;
    transform: translate(-50%, 0);
}
</style>
React
App.js
App.css
import React, { useState } from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';
import './App.css';

import {
    DataGrid,
    Column,
    // ...
    Selection
} from 'devextreme-react/data-grid';

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 = (e) => {
        e.component.byKey(e.currentSelectedRowKeys[0]).done(employee => {
            setSelectedEmployee(employee);
        });
    }

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

export default App;
/* ... */
.App {
    width: 900px;
    position: relative;
}

#selected-employee {
    position: absolute;
    left: 50%;
    transform: translate(-50%, 0);
}

In the next step, we will add a summary to count grid records.

Display Summaries

Summaries display a synopsis of grid data. All summaries can be divided into two groups:

  • Total summaries
    Calculated by values from the whole grid or a single column; configured in the totalItems array.

  • Group summaries
    Calculated by values from each group; configured in the groupItems array.

Each summary item displays a value that is a product of applying an aggregate function to data. The DataGrid supports predefined aggregate functions, such as "sum", "avg", and "count", and allows you to implement a custom aggregate function. To specify the applied aggregate function, set the summaryType option.

The code below configures a group summary that counts grid records in each group:

jQuery
index.js
$(function() {
    $("#dataGrid").dxDataGrid({
        // ...
        summary: {
            groupItems: [{
                summaryType: "count"
            }]
        },
    });
});
Angular
app.component.html
<dx-data-grid ... >
    <!-- ... -->
    <dxo-summary>
        <dxi-group-item
            summaryType="count">
        </dxi-group-item>
    </dxo-summary>
</dx-data-grid>
Vue
App.vue
<template>
    <div id="app-container">
        <DxDataGrid ... >
            <!-- ... -->
            <DxSummary>
                <DxGroupItem
                    summary-type="count"
                />
            </DxSummary>
        </DxDataGrid>
    </div>
</template>

<script>
import {
    DxDataGrid,
    // ...
    DxSummary,
    DxGroupItem
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        // ...
        DxSummary,
        DxGroupItem
    },
    // ...
}
</script>
React
App.js
import React, { useState } from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';
import './App.css';

import {
    DataGrid,
    Column,
    // ...
    Summary,
    GroupItem
} from 'devextreme-react/data-grid';

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

export default App;

In the following step, we will add an expandable section that displays information about an employee to each grid row.

Configure the Master-Detail Interface

The master-detail interface adds an expandable section that contains detail data ("detail section") to a standard data row ("master row"). The detail section can contain anything.

Master-detail data representation is configured in the masterDetail object. To specify detail sections' contents, implement the template. Users can expand and collapse details sections if you set the enabled option to true:

jQuery
index.js
data.js
index.css
$(function() {
    $("#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);
            }
        },
    });
});
const employees = [{
    "EmployeeID": 1,
    "FullName": "Nancy Davolio",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1968-12-08T00:00:00.000Z",
    "HireDate": "2011-05-01T00:00:00.000Z",
    "Address": "507 - 20th Ave. E.\r\nApt. 2A",
    "City": "Seattle",
    "Region": "WA",
    "PostalCode": "98122",
    "Country": "USA",
    "HomePhone": "(206) 555-9857",
    "Extension": "5467",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/06.png",
    "Notes": "Education includes a BA in psychology from Colorado State University in 1990.  She also completed \"The Art of the Cold Call.\"  Nancy is a member of Toastmasters International.",
    "ReportsTo": 2
},
// ...
];
.employee-photo {
    height: 140px;
    float: left;
    padding: 0 20px 20px 0;
}

.employee-notes {
    text-align: justify;
    white-space: normal;
}

/* ... */
Angular
app.component.html
employees.service.ts
app.component.css
<dx-data-grid ... >
    <!-- ... -->
    <dxo-master-detail
        [enabled]="true"
        [template]="'employee-info'">
    </dxo-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>
// ...
const employees: Employee[] = [{
    "EmployeeID": 1,
    "FullName": "Nancy Davolio",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1968-12-08T00:00:00.000Z",
    "HireDate": "2011-05-01T00:00:00.000Z",
    "Address": "507 - 20th Ave. E.\r\nApt. 2A",
    "City": "Seattle",
    "Region": "WA",
    "PostalCode": "98122",
    "Country": "USA",
    "HomePhone": "(206) 555-9857",
    "Extension": "5467",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/06.png",
    "Notes": "Education includes a BA in psychology from Colorado State University in 1990.  She also completed \"The Art of the Cold Call.\"  Nancy is a member of Toastmasters International.",
    "ReportsTo": 2
},
// ...
];
// ...
.employee-photo {
    height: 140px;
    float: left;
    padding: 0 20px 20px 0;
}

.employee-notes {
    text-align: justify;
    white-space: normal;
}

/* ... */
Vue
App.vue
employees.service.js
<template>
    <div id="app-container">
        <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>
    </div>
</template>

<script>
import {
    DxDataGrid,
    // ...
    DxMasterDetail
} from 'devextreme-vue/data-grid';

export default {
    components: {
        DxDataGrid,
        // ...
        DxMasterDetail
    },
    // ...
}
</script>

<style>
.employee-photo {
    height: 140px;
    float: left;
    padding: 0 20px 20px 0;
}

.employee-notes {
    text-align: justify;
    white-space: normal;
}

/* ... */
</style>
const employees = [{
    "EmployeeID": 1,
    "FullName": "Nancy Davolio",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1968-12-08T00:00:00.000Z",
    "HireDate": "2011-05-01T00:00:00.000Z",
    "Address": "507 - 20th Ave. E.\r\nApt. 2A",
    "City": "Seattle",
    "Region": "WA",
    "PostalCode": "98122",
    "Country": "USA",
    "HomePhone": "(206) 555-9857",
    "Extension": "5467",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/06.png",
    "Notes": "Education includes a BA in psychology from Colorado State University in 1990.  She also completed \"The Art of the Cold Call.\"  Nancy is a member of Toastmasters International.",
    "ReportsTo": 2
},
// ...
];
React
App.js
employees.js
App.css
import React, { useState } from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';
import './App.css';

import {
    DataGrid,
    Column,
    // ...
    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 (
        <div className="App">
            <DataGrid ... >
                {/* ... */}
                <MasterDetail
                    enabled={true}
                    component={DetailSection}
                />
            </DataGrid>
        </div>
    );
}

export default App;
export const employees = [{
    "EmployeeID": 1,
    "FullName": "Nancy Davolio",
    "Position": "Sales Representative",
    "TitleOfCourtesy": "Ms.",
    "BirthDate": "1968-12-08T00:00:00.000Z",
    "HireDate": "2011-05-01T00:00:00.000Z",
    "Address": "507 - 20th Ave. E.\r\nApt. 2A",
    "City": "Seattle",
    "Region": "WA",
    "PostalCode": "98122",
    "Country": "USA",
    "HomePhone": "(206) 555-9857",
    "Extension": "5467",
    "Photo": "https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/06.png",
    "Notes": "Education includes a BA in psychology from Colorado State University in 1990.  She also completed \"The Art of the Cold Call.\"  Nancy is a member of Toastmasters International.",
    "ReportsTo": 2
},
// ...
];
/* ... */
.employee-photo {
    height: 140px;
    float: left;
    padding: 0 20px 20px 0;
}

.employee-notes {
    text-align: justify;
    white-space: normal;
}

Run the code and click the Expand button in any row. You should see a detail section that contains an employee's photo and information.

Export Data to Excel

DevExtreme includes a static method exportDataGrid(options) that exports grid data to the Excel format. Its minimum configuration requires a DataGrid instance and an Excel worksheet to which grid data should be exported. After the export, you should save the data to an Excel file.

To create and manage worksheets and save Excel files, this feature requires the following third-party libraries:

The DataGrid includes an export UI. This tutorial uses it to call the exportDataGrid(options) method. Enable the UI by setting the export.enabled option to true and call exportDataGrid(options) inside the DataGrid's onExporting event handler. You should also set the e.cancel parameter to true to disable the deprecated built-in export functionality.

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://cdnjs.cloudflare.com/ajax/libs/exceljs/4.0.1/exceljs.min.js"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.2/FileSaver.min.js"></script>

        <!-- DevExtreme scripts are referenced here -->
        <!-- ... -->
    </head>
</html>
$(function() {
    $("#dataGrid").dxDataGrid({
        // ...
        export: {
            enabled: true
        },
        onExporting: function(e) { 
            const workbook = new ExcelJS.Workbook(); 
            const worksheet = workbook.addWorksheet("Main sheet"); 
            DevExpress.excelExporter.exportDataGrid({ 
                worksheet: worksheet, 
                component: e.component,
            }).then(function() {
                workbook.xlsx.writeBuffer().then(function(buffer) { 
                    saveAs(new Blob([buffer], { type: "application/octet-stream" }), "DataGrid.xlsx"); 
                }); 
            }); 
            e.cancel = true; 
        }
    });
});
Angular
Installation command
tsconfig.app.json
app.component.html
app.component.ts
npm install --save exceljs file-saver
{
    // ...
    "compilerOptions": {
        // ...
        "paths": {
            // ...
            "exceljs": [
                "node_modules/exceljs/dist/exceljs.js"
            ]
        }
    },
    // ...
}
<dx-data-grid ...
    (onExporting)="exportGrid($event)">
    <!-- ... -->
    <dxo-export [enabled]="true"></dxo-export>
</dx-data-grid>
// ...
import { Workbook } from 'exceljs';
import saveAs from 'file-saver';
import { exportDataGrid } from 'devextreme/excel_exporter';

// ...
export class AppComponent {
    // ...
    exportGrid(e) {
        const workbook = new Workbook(); 
        const worksheet = workbook.addWorksheet("Main sheet"); 
        exportDataGrid({ 
            worksheet: worksheet, 
            component: e.component
        }).then(function() {
            workbook.xlsx.writeBuffer().then(function(buffer: BlobPart) { 
                saveAs(new Blob([buffer], { type: "application/octet-stream" }), "DataGrid.xlsx"); 
            }); 
        }); 
        e.cancel = true; 
    }
}
Vue
Installation command
App.vue
npm install --save exceljs file-saver
<template>
    <div id="app-container">
        <DxDataGrid ...
            @exporting="exportGrid">
            <!-- ... -->
            <DxExport :enabled="true" />
        </DxDataGrid>
    </div>
</template>

<script>
import {
    DxDataGrid,
    // ...
    DxExport
} from 'devextreme-vue/data-grid';
import { Workbook } from 'exceljs';
import saveAs from 'file-saver';
import { exportDataGrid } from 'devextreme/excel_exporter';

export default {
    components: {
        DxDataGrid,
        // ...
        DxExport
    },
    // ...
    methods: {
        exportGrid(e) {
            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"); 
                }); 
            }); 
            e.cancel = true; 
        }
    }
}
</script>

<style>
/* ... */
</style>
React
Installation command
App.js
npm install --save exceljs file-saver
import React, { useState } from 'react';
import 'devextreme/dist/css/dx.common.css';
import 'devextreme/dist/css/dx.light.css';
import './App.css';

import {
    DataGrid,
    Column,
    // ...
    Export
} from 'devextreme-react/data-grid';

import { Workbook } from 'exceljs';
import saveAs from 'file-saver';
import { exportDataGrid } from 'devextreme/excel_exporter';
// ...

function exportGrid(e) {
    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"); 
        }); 
    });
    e.cancel = true; 
}

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

export default App;

Run the code and click the Export button in the upper-right corner. Grid data should be exported to the DataGrid.xlsx file.

The exportDataGrid(options) method can be called at any point in your application, not necessarily using the DataGrid's export UI. For example, you can implement a standalone button and call this method when the button is clicked.

You have now configured core DataGrid features. For more details on this widget, explore the following resources: