All docs
V22.1
24.1
23.2
23.1
22.2
22.1
21.2
21.1
20.2
20.1
19.2
The page you are viewing does not exist in version 19.2.
19.1
The page you are viewing does not exist in version 19.1.
18.2
The page you are viewing does not exist in version 18.2.
18.1
The page you are viewing does not exist in version 18.1.
17.2
The page you are viewing does not exist in version 17.2.
A newer version of this page is available. Switch to the current version.

jQuery DataGrid - Getting Started

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.

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 following GitHub repository: getting-started-with-datagrid.

Create a DataGrid

jQuery

Add DevExtreme to your jQuery application and use the following code to create a 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/22.1.13/css/dx.light.css">
        <link rel="stylesheet" href="index.css">

        <script type="text/javascript" src="https://cdn3.devexpress.com/jslib/22.1.13/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 a 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 a DataGrid:

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

<script>
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 a DataGrid:

App.js
App.css
import React from 'react';
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 load and update data from different data source types. To use a local array, assign it to the dataSource property and specify the key field in the keyExpr property. 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.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, a DataGrid is created with a column for each data field. All the columns have equal widths and the same order as their data fields.

Customize Columns

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

Reorder Columns

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

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.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 because BirthDate and HireDate are stored as strings, but you want the DataGrid to treat them as date-time values.

Resize Columns

Grid columns have equal widths by default. You can set each column's width or indicate that all columns should adjust their widths to their content (columnAutoWidth). Users can resize columns if you enable the allowColumnResizing property.

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.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 UI component's width, users can scroll the grid horizontally. If you set the columnFixing.enabled property to true, users can show certain columns in the view regardless of how far they scroll the grid.

You can also enable a column's fixed property in code. This fixes the column to the UI component's left edge. To change the position, set the fixedPosition property.

The following code fixes the FullName column to the default position and allows 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.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 property to false. Hidden columns appear in the columnChooser. Users can restore hidden columns from it. To enable the column chooser, set the columnChooser.enabled property to true. If a column should not be visible even in the column chooser, 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.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;

Sort Data

The sorting.mode property specifies whether users can sort grid records by single or multiple columns. This tutorial uses the default sorting mode - single.

You can also set a column's sortOrder and sortIndex properties to specify the 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.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.

Filter and Search Data

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

In this tutorial, the filterRow and searchPanel are displayed:

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.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 in a filter row cell or the search panel. Grid data is filtered according to this value.

Group Data

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

To group data in code, specify a column's groupIndex property. 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.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, 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.

Edit and Validate Data

Users can add new records and update or delete existing records. To allow these operations, enable the allowAdding, allowUpdating, and allowDeleting properties in the editing object. Multiple edit modes are available. This tutorial uses the pop-up edit mode.

DevExtreme includes a validation engine that checks 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 use multiple rules. The code below assigns the Required rule to several columns.

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.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. This invokes a pop-up window that contains an edit form. When you clear the Full Name text box on this form, the following validation error is shown: "Full Name is required".

Select Records

The DataGrid supports single and multiple record selection modes. Use the selection.mode property to specify the mode.

You can obtain 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, { useCallback, useState } from 'react';
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 = useCallback((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);
}

Display Summaries

Summaries can be divided into two groups:

  • 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 displays a value that is the result of applying an aggregate function to data. You can use predefined aggregate functions, such as "sum", "avg", and "count", or implement a custom aggregate function. To apply an aggregate function, set the summaryType property.

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.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;

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.

jQuery
index.js
$(function() {
    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");
});
Angular
app.component.html
app.component.ts
app.module.ts
<div id="app-container">
    <dx-data-grid ... >
        <!-- ... -->
        <dxo-grouping [autoExpandAll]="expanded"></dxo-grouping>
        <dxo-toolbar>
            <dxi-item name="groupPanel"></dxi-item>
            <dxi-item location="after">
                <dx-button
                    [text]="expanded ? 'Collapse All' : 'Expand All'"
                    [width]="136"
                    (onClick)="expanded = !expanded">
                </dx-button>
            </dxi-item>
            <dxi-item name="addRowButton" showText="always"></dxi-item>
            <dxi-item name="exportButton"></dxi-item>
            <dxi-item name="columnChooserButton"></dxi-item>
            <dxi-item name="searchPanel"></dxi-item>
        </dxo-toolbar>
    </dx-data-grid>
</div>
// ...
@Component({
    // ...
})
export class AppComponent {
    // ...
    expanded: Boolean = true;
}
import {
    // ...
    DxButtonModule
} from 'devextreme-angular';

@NgModule({
    // ...
    imports: [
        // ...
        DxButtonModule
    ],
})
export class AppModule { }
Vue
App.vue
<template>
    <div id="app-container">
        <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>
    </div>
</template>

<script>
import {
    DxDataGrid,
    // ...
    DxGrouping,
    DxToolbar,
    DxItem
} from 'devextreme-vue/data-grid';
import { DxButton } from 'devextreme-vue/button';

export default {
    components: {
        DxDataGrid,
        // ...
        DxGrouping,
        DxToolbar,
        DxItem,
        DxButton
    },
    data() {
        return {
            // ...
            expanded: true
        }
    },
    // ...
}
</script>

<style>
/* ... */
</style>
React
App.js
import React, { useState } from 'react';
import 'devextreme/dist/css/dx.light.css';
import './App.css';

import {
    DataGrid,
    // ...
    Grouping,
    Toolbar,
    Item
} from 'devextreme-react/data-grid';
import { Button } from 'devextreme-react/button';

// ...

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

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

export default App;

Configure Master-Detail Interface

DataGrid allows you to display expandable detail sections under data rows. To configure a UI like this, use the masterDetail object. Set the enabled property to true and specify a template that is used as the detail section's content:

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.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

The DataGrid allows users to export grid data as Excel and PDF documents. This feature requires the following third-party libraries:

To configure export operations, use the excelExporter.exportDataGrid(options) or pdfExporter.exportDataGrid(options) method. It requires a DataGrid instance and a target Excel worksheet or a PDF document. You can call these methods at any point in your application.

The following code calls export methods in the DataGrid's onExporting event handler. The control executes this handler when users select one of the operations available in the Export button drop-down menu. The export.enabled property adds this button to the DataGrid. Use the formats property to configure available export operation types.

When users click "Export all data to Excel", excelExporter.exportDataGrid(options) exports grid data as a blob that is then saved to an XLSX file. The e.cancel parameter disables the deprecated built-in export functionality.

When users click "Export all data to PDF", pdfExporter.exportDataGrid(options) exports grid data as a PDF document.

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>
        <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: 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;
            } 
            else if (e.format === 'pdf') {
                const doc = new jsPDF();
                DevExpress.pdfExporter.exportDataGrid({
                    jsPDFDocument: doc,
                    component: e.component,
                }).then(() => {
                    doc.save('DataGrid.pdf');
                });
            }
        }
    });
});
Angular
Installation command
tsconfig.app.json
app.component.html
app.component.ts
npm install --save exceljs file-saver
npm install jspdf
{
    // ...
    "compilerOptions": {
        // ...
        "paths": {
            // ...
            "exceljs": [
                "node_modules/exceljs/dist/exceljs.min.js"
            ]
        }
    },
    // ...
}
<dx-data-grid ...
    (onExporting)="exportGrid($event)">
    <!-- ... -->
    <dxo-export 
        [enabled]="true"
        [formats]="['xlsx', 'pdf']"
    >
    </dxo-export>
</dx-data-grid>
// ...
import { Workbook } from 'exceljs';
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) {
        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"); 
                }); 
            }); 
            e.cancel = true;
        } 
        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 exceljs file-saver
npm install jspdf
<template>
    <DxDataGrid ...
        @exporting="exportGrid">
        <!-- ... -->
        <DxExport
            :enabled="true"
            :formats="['xlsx', 'pdf']"
        />
    </DxDataGrid>
</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';
import { jsPDF } from 'jspdf';
import { exportDataGrid as exportDataGridToPdf} from 'devextreme/pdf_exporter';

export default {
    components: {
        DxDataGrid,
        // ...
        DxExport
    },
    // ...
    methods: {
        exportGrid(e) {
            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"); 
                    }); 
                }); 
                e.cancel = true;
            } 
            else if (e.format === 'pdf') {
                const doc = new jsPDF();
                exportDataGridToPdf({
                    jsPDFDocument: doc,
                    component: e.component,
                }).then(() => {
                    doc.save('DataGrid.pdf');
                });
            }
        }
    }
}
</script>

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

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

import { Workbook } from 'exceljs';
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) {
    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"); 
            }); 
        }); 
        e.cancel = true;
    } 
    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 default App;

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 further information on the DataGrid component, refer to the following resources: