Getting Started with the KendoReact Data Grid
Welcome to the KendoReact Data Grid!
After completing this tutorial, you will have learned the basic concepts and configuration of the Grid, and you will have developed the following sample app:
tip If you prefer video, watch the React Data Grid Video Tutorial.
Before You Begin
npx create-react-app my-app --template typescript
npm start
This guide requires that you have basic knowledge of React and TypeScript, and that you have already created [a blank React project]({% slug getting_started %}). If you are starting from a Next.js project, you need to use the KendoReact Server Data Grid.
For the best results, follow the guide step-by-step.
tip You can speed up the development of your KendoReact Data Grid application with the Kendo UI Template Wizard for Visual Studio Code.
Install the Component
npm i @progress/kendo-react-grid @progress/kendo-data-query @progress/kendo-react-data-tools @progress/kendo-react-inputs @progress/kendo-react-intl @progress/kendo-react-dropdowns @progress/kendo-react-dateinputs @progress/kendo-drawing @progress/kendo-react-animation @progress/kendo-licensing @progress/kendo-react-buttons @progress/kendo-react-treeview @progress/kendo-react-popup @progress/kendo-svg-icons
npm i @progress/kendo-theme-default
Run these commands in the root of your React project to install the KendoReact Data Grid and its dependencies, and the Kendo UI Default theme.
Import the Component
import { Grid, GridColumn as Column } from "@progress/kendo-react-grid";
import "@progress/kendo-theme-default/dist/all.css";
Place the import
statements in the App component file (for example: src/App.tsx
) for your project.
Note that you are also importing the GridColumn
component, but under the Column
alias.
Use the Component
Using the KendoReact Data Grid requires either a commercial license key or an active trial license key. Follow the instructions on the KendoReact My License page to activate your license.
The KendoReact Data Grid is a powerful tool for creating responsive, accessible, and customizable applications that require the displaying and management of large datasets. This section will take you through a basic Data Grid setup workflow, starting with the column definition and ending with some basic styling.
Load and Show Data
import products from "./shared-gd-products.json";
const App = () => {
return (
<Grid data={products}>
</Grid>
);
}
export default App;
- Use the dataset from the demo source files at the top of the guide to create a
shared-gd-products.json
file locally in your project. - Use an
import
statement to reference the data file. - Add a
<Grid>
definition. - Use the
data
prop to load the data in your Data Grid.
You now have a simple grid that shows all the data from shared-gd-products.json
.
Define Columns
<Grid data={products}>
<Column field="ProductID" title="ID" />
<Column field="ProductName" title="Name"/>
<Column field="Category.CategoryName" title="Category" />
<Column field="UnitPrice" title="Price" />
<Column field="UnitsInStock" title="In stock" />
<Column field="Discontinued" title="Discontinued" />
</Grid>
- For every column that you want to show, add a
<Column>
definition. Note thatColumn
is an alias forGridColumn
. - Use the
field
prop to bind the column to the respective data field in your data set. For nested fields, use aparent.child
notation (for example:Category.CategoryName
). - Use the
title
prop to set a custom title for the column. If not set, the title defaults to the name of the field.
You now have a grid that shows a sub-set of the data and has custom column names.
Add Pagination
import React, { useState } from 'react';
import { Grid, GridColumn as Column, GridDataStateChangeEvent } from "@progress/kendo-react-grid";
import { process, State, DataResult } from "@progress/kendo-data-query";
import "@progress/kendo-theme-default/dist/all.css";
import products from "./shared-gd-products.json";
const App = () => {
const initialDataState: State = {
take: 10,
skip: 0
};
const [dataState, setDataState] = useState<State>(initialDataState);
const handleDataStateChange = (event: GridDataStateChangeEvent) => {
setDataState(event.dataState);
};
return (
<Grid
data={process(products, dataState) as DataResult}
pageable={true}
skip={dataState.skip}
take={dataState.take}
total={products.length}
{...dataState}
onDataStateChange={handleDataStateChange}
>
<Column field="ProductID" title="ID" />
<Column field="ProductName" title="Name"/>
<Column field="Category.CategoryName" title="Category" />
<Column field="UnitPrice" title="Price" />
<Column field="UnitsInStock" title="In stock" />
<Column field="Discontinued" title="Discontinued" />
</Grid>
);
}
export default App;
-
Add the
import
statements required for data handling. You now also need the [Data Query(https://www.telerik.com/kendo-react-ui/components/dataquery/)] package to handle your data operations.import React, { useState } from 'react'; import { Grid, GridColumn as Column, GridDataStateChangeEvent } from "@progress/kendo-react-grid"; import { process, State, DataResult } from "@progress/kendo-data-query";
-
Inside your
App
, define the initial state of your data. For example, rendering only the first 10 items of the data set. Note the use of theskip
andtake
props of the<Grid>
which are responsible for calculating the current page and the number of items shown.const initialDataState: State = { take: 10, skip: 0 };
-
Add the logic that handles your data operations affecting the state of the Grid.
Because this guide will introduce you to multiple data operations, the example uses theprocess
method and theonDataStateChange
event. Both are the recommended practice when implementing multiple data operations within the same Data Grid.const [dataState, setDataState] = useState<State>(initialDataState); const handleDataStateChange = (event: GridDataStateChangeEvent) => { setDataState(event.dataState); };
-
Re-define your data source, pass the Grid state as a prop, and configure some additional
<Grid>
props to enable pagination.pageable
enables the built-in pager.skip
helps calculate the current page.take
determines how many items are rendered on the page.total
defines the total number of records in the dataset.onDataStateChange
fires when the data state of the Grid changes.
<Grid data={process(products, dataState) as DataResult} pageable={true} skip={dataState.skip} take={dataState.take} total={products.length} {...dataState} onDataStateChange={onDataStateChange} >
Note that after the initial definition of your Grid state change handling, you no longer need to make any changes.
You now have a grid with enabled pagination.
Enable Filtering
...
const initialDataState: State = {
take: 10,
skip: 0,
filter: undefined
};
...
<Grid
...
filterable={true}
filter={dataState.filter}
...
>
...
</Grid>
- Update your initial data state to include the
filter
prop. This example sets it asundefined
to show the data unfiltered, but you can pre-define your own filter logic instead. - Configure the
<Grid>
props to enable filtering.filterable
enables the built-in filter row, rendered right below the column titles.filter
is the descriptor by which the data is filtered.
Enable Sorting
...
const initialDataState: State = {
take: 10,
skip: 0,
filter: undefined,
sort: undefined
};
...
<Grid
...
sortable={true}
sort={dataState.sort}
...
>
</Grid>
- Update your initial data state to include the
sort
prop. This example sets it asundefined
to show the data unsorted, but you can pre-define your own sorting logic instead. - Configure the
<Grid>
props to enable sorting.sortable
enables the built-in sorting which triggers when you click the column title. When the column is sorted, an arrow indicating the sorting direction shows next to the column title.sort
is the descriptor by which the data is sorted.
You now have a grid with enabled filtering.
Show Custom Content
import { ..., GridCustomCellProps } from "@progress/kendo-react-grid";
...
const categoryNameEmoticons: { [key: string]: string } = {
'Beverages': '🍹',
'Condiments': '🥫',
'Confections': '🍬',
'Dairy Products': '🥛',
'Grains/Cereals': '🌾',
'Meat/Poultry': '🍗',
'Produce': '🥕',
'Seafood': '🐟',
};
const EmoticonCell = (props: GridCustomCellProps) => {
const emoticon = categoryNameEmoticons[props.dataItem.Category.CategoryName] || '❓';
return (
<td>
<span style={{ fontSize: '16px', marginRight: '8px' }}>{emoticon}</span>
{props.dataItem.Category.CategoryName}
</td>
);
};
...
<Column field="Category.CategoryName" title="Category" cell={EmoticonCell} />
-
Add the
import
statement for theGridCustomCellProps
component. -
Add the logic that maps your product categories to a visual representation (via emoticons). Note that you need to explicitly set the types for the mappings.
const categoryNameEmoticons: { [key: string]: string } = { 'Beverages': '🍹', 'Condiments': '🥫', 'Confections': '🍬', 'Dairy Products': '🥛', 'Grains/Cereals': '🌾', 'Meat/Poultry': '🍗', 'Produce': '🥕', 'Seafood': '🐟', };
-
Add the logic that creates your custom cell. Note that you need to replace the entire cell (
<td>
block) and not just its contents. This example also sets a default emoticon to use if there's no mapping for the category.const EmoticonCell = (props: GridCustomCellProps) => { const categoryEmoticon = categoryNameEmoticons[props.dataItem.Category.CategoryName] || '❓'; return ( <td> <span style={{ fontSize: '16px', marginRight: '8px' }}>{categoryEmoticon}</span> {props.dataItem.Category.CategoryName} </td> ); };
-
Update your
<Column>
definition and set thecell
prop to render your custom cells.<Grid data={dataResult} pageable={true} skip={dataState.skip} take={dataState.take} total={products.length} filterable={true} filter={dataState.filter} sortable={true} sort={dataState.sort} onDataStateChange={onDataStateChange} > <Column field="ProductID" title="ID" /> <Column field="ProductName" title="Name" /> <Column field="Category.CategoryName" title="Category" cell={EmoticonCell} /> <Column field="UnitPrice" title="Price" /> <Column field="UnitsInStock" title="In stock" /> </Grid>
You now have a grid with a column that renders additional content in its cells.
Enable Inline Editing
import React, { useState } from 'react';
import {
Grid,
GridColumn as Column,
GridCustomCellProps,
GridItemChangeEvent,
GridRowClickEvent,
GridDataStateChangeEvent,
} from "@progress/kendo-react-grid";
import {
process,
State,
DataResult
} from "@progress/kendo-data-query";
import "@progress/kendo-theme-default/dist/all.css";
import products from "./shared-gd-products.json";
interface ProductCategory {
CategoryID?: number;
CategoryName?: string;
Description?: string;
}
interface Product {
ProductID: number;
ProductName?: string;
SupplierID?: number;
CategoryID?: number;
QuantityPerUnit?: string;
UnitPrice?: number;
UnitsInStock?: number;
UnitsOnOrder?: number;
ReorderLevel?: number;
Discontinued?: boolean;
Category?: ProductCategory;
inEdit?: boolean | string;
}
const categoryNameEmoticons: { [key: string]: string } = {
'Beverages': '🍹',
'Condiments': '🥫',
'Confections': '🍬',
'Dairy Products': '🥛',
'Grains/Cereals': '🌾',
'Meat/Poultry': '🍗',
'Produce': '🥕',
'Seafood': '🐟',
};
const EmoticonCell = (props: GridCustomCellProps) => {
const categoryEmoticon = categoryNameEmoticons[props.dataItem.Category.CategoryName] || '❓';
return (
<td>
<span style={{ fontSize: '16px', marginRight: '8px' }}>{categoryEmoticon}</span>
{props.dataItem.Category.CategoryName}
</td>
);
};
const App = () => {
const initialDataState: State = {
take: 10,
skip: 0,
filter: undefined,
sort: undefined
};
const [dataState, setDataState] = useState<State>(initialDataState);
const [data, setData] = useState<Array<Product>>(products);
const [editID, setEditID] = useState<number | null>(null);
const handleDataStateChange = (event: GridDataStateChangeEvent) => {
setDataState(event.dataState);
};
const handleRowClick = (event: GridRowClickEvent) => {
setEditID(event.dataItem.ProductID);
};
const handleItemChange = (event: GridItemChangeEvent) => {
const inEditID = event.dataItem.ProductID;
const field = event.field || "";
const newData = data.map((item) =>
item.ProductID === inEditID ? { ...item, [field]: event.value } : item
);
setData(newData);
};
return (
<Grid
data={{
...process(data, dataState) as DataResult,
data: process(data, dataState).data.map((item: Product) => ({
...item,
inEdit: item.ProductID === editID,
})),
}}
pageable={true}
skip={dataState.skip}
take={dataState.take}
total={products.length}
filterable={true}
filter={dataState.filter}
sortable={true}
sort={dataState.sort}
editField="inEdit"
onItemChange={handleItemChange}
onDataStateChange={handleDataStateChange}
onRowClick={handleRowClick}
{...dataState}
>
<Column field="ProductID" title="ID" editable={false} />
<Column field="ProductName" title="Name" editor="text"/>
<Column field="Category.CategoryName" title="Category" cell={EmoticonCell} editable={false} />
<Column field="UnitPrice" title="Price" editor="numeric" />
<Column field="UnitsInStock" title="In stock" editor="numeric" />
<Column field="Discontinued" title="Discontinued" editor="boolean" />
</Grid>
);
}
export default App;
-
Add the
import
statements forGridItemChangeEvent
andGridRowClickEvent
. -
Define interfaces for the data in your
shared-gd-products.json
file. Define the type for every data field from the dataset and add the booleaninEdit
property. You will later use it to indicate if the item is being edited.interface ProductCategory { CategoryID?: number; CategoryName?: string; Description?: string; } interface Product { ProductID: number; ProductName?: string; SupplierID?: number; CategoryID?: number; QuantityPerUnit?: string; UnitPrice?: number; UnitsInStock?: number; UnitsOnOrder?: number; ReorderLevel?: number; Discontinued?: boolean; Category?: ProductCategory; inEdit?: boolean | string; }
-
Add logic that handles row clicks. Set your
editID
to theProductID
of the current data item.const [editID, setEditID] = useState<number | null>(null); const handleRowClick = (event: GridRowClickEvent) => { setEditID(event.dataItem.ProductID); };
-
Add logic that handles the item editing.
const [data, setData] = useState<Array<Product>>(products); const handleItemChange = (event: GridItemChangeEvent) => { const inEditID = event.dataItem.ProductID; const field = event.field || ""; const newData = data.map((item) => item.ProductID === inEditID ? { ...item, [field]: event.value } : item ); setData(newData); };
-
Configure the
<Grid>
props to enable editing.- Update your data binding.
- Set the
editField
prop to enable editing. - Set the
onItemChange
andonRowClick
props to finish your event handling.
<Grid data={{ ...process(data, dataState) as DataResult, data: process(data, dataState).data.map((item: Product) => ({ ...item, inEdit: item.ProductID === editID, })), }} pageable={true} skip={dataState.skip} take={dataState.take} total={products.length} filterable={true} filter={dataState.filter} sortable={true} sort={dataState.sort} editField="inEdit" onItemChange={handleItemChange} onDataStateChange={handleDataStateChange} onRowClick={handleRowClick} {...dataState} >
-
Update your
<Column>
definitions.- Set
editable={false}
for the ID and Category columns. This disables editing for the cells in the respective columns. - Set the
editor
prop for the other<Column>
s.
<Column field="ProductID" title="ID" editable={false} /> <Column field="ProductName" title="Name" editor="text"/> <Column field="Category.CategoryName" title="Category" cell={EmoticonCell} editable={false} /> <Column field="UnitPrice" title="Price" editor="numeric" /> <Column field="UnitsInStock" title="In stock" editor="numeric" /> <Column field="Discontinued" title="Discontinued" editor="boolean" />
- Set
You now have a grid with enabled editing.
Style the Component
tip Are you looking for guidance around how to create visually appealing and consistent user interfaces with Telerik UI components? Check out the Progress Design System.
With the import "@progress/kendo-theme-default/dist/all.css";
statement present in your code, you already have professionally designed styling applied to your app out-of-box. In this section, you will learn how to customize the look and feel of your KendoReact Data Grid.
This guide shows you how you can apply inline styling directly to the component or by using the KendoReact Data Grid or the Kendo Default theme styling variables.
For more information and additional approaches to styling, see KendoReact Data Grid Styling Basics.
Enable Responsive Design
Currently, the KendoReact Data Grid does not provide an explicit setting for responsive design. However, out-of-the-box the Data Grid columns will resize to accommodate any changes in your screen size. You can also configure the separate Grid components to be responsive (for example, the pager). Additionally, you can implement your own customizations to make various elements of the Data Grid more responsive.
If you are looking to create a more compact KendoReact Grid, check the size prop
.
Customize the Theme
tip ThemeBuilder helps you achieve a unique appearance for your React apps and delivers full control over the visual elements of the KendoReact UI components.
This project already relies on the Kendo Default theme. It provides neutral styling which you can customize to fit your design needs.
To customize the theme:
- In the root of the project, install the
@progress/kendo-theme-core
package. It provides a collection of functions and mixins that will help you customize your theme.
npm i @progress/kendo-theme-core
- In the root of the project, install the
Sass
package.
npm i sass
- Inside your project, create a
custom-theme.scss
file and replace the Kendo theme import with it.
// In your custom-theme.scss
@import '@progress/kendo-theme-core/scss/functions/index.import.scss';
// All custom SCSS will between the @import statements
@import '@progress/kendo-theme-default/dist/all.scss';
// In your app code
import './custom-theme.scss';
Change the Theme Colors
@import '@progress/kendo-theme-core/scss/functions/index.import.scss';
$kendo-colors: ();
$kendo-colors: k-map-merge(
$kendo-colors,
k-generate-color-variations('primary', #2B2BB2, 'default'),
k-map-set($kendo-colors, on-app-surface, #00216B)
);
@import '@progress/kendo-theme-default/dist/all.scss';
- Create an empty
$kendo-colors
map. All your theme colors are defined through the variables in the$kendo-colors
map. - Merge your new map with the existing definition for the Default theme. In your new map, re-generate the
primary
palette of thedefault
theme based on the#2B2BB2
color. Manually set the$kendo-colors-on-app-surface
variable to the#00216B
.
You now have a restyled Data Grid that uses a set of custom blue hues. The colors apply to all major elements and interactions.
Style the Fonts
$kendo-font-size: 1rem;
$kendo-font-family: Helvetica;
Set the font size in your custom-theme.scss
.
Your grid now uses a larger font size. For a complete list of the available typography variables, see Customizing Typography.
Style the Header
.k-column-title {
font-weight: 700;
font-size: 18px;
}
Instead of the built-in variables, you can also customize your code using CSS selectors in custom-theme.scss
. Apply a new size and font weight for your column titles via the .k-column-title
class.
You now have a more prominent header.
Style Columns
<Column field="ProductID" title="ID" editable={false} filterable={false} width="75px" />
<Column field="ProductName" title="Name" editor="text" />
<Column field="Category.CategoryName" title="Category" cell={EmoticonCell} editable={false} width="300px"/>
<Column field="UnitPrice" title="Price" editor="numeric" width="150px"/>
<Column field="UnitsInStock" title="In stock" editor="numeric" width="150px"/>
<Column field="Discontinued" title="Discontinued" editor="boolean" width="150px" />
Set your column widths inline in their <Column>
definitions. Note that this example also disables filtering by ID by setting fitlerable={false}
for the ID column.
You now have a Data Grid with fixed column widths. You can also use the className prop
to apply a styling class to the respective column.
Style Rows
$kendo-grid-alt-bg: #DCECFF;
In custom-theme.scss
, change the background color of your alternating rows. You can use one of the built-in Grid styling variables. For a complete list of the styling variables for the React grid, see Customizing Grid.
You now have your alternating rows show a different background color. You can also use the rowRender function
to modify the appearance of the rows.
KendoReact Data Grid APIs
KendoReact Data Grid Dependencies
The Grid package requires you to install the following peer dependencies in your application:
Package Name | Description |
---|---|
react 16.8.2* | Contains the functionality necessary to define React components. |
react-dom | Contains the React renderer for the web. |
@progress/kendo-licensing | Contains the internal infrastructure related to licensing. |
@progress/kendo-react-intl | Contains the KendoReact Internationalization package that applies the desired cultures by providing services and pipes for the parsing and formatting of dates and numbers. |
@progress/kendo-data-query | Applies sorting, filtering, grouping, and aggregate data operations. |
@progress/kendo-react-animation | Enables the animations in the KendoReact components. |
@progress/kendo-react-data-tools | Delivers components required to manage and control the data in the application. |
@progress/kendo-react-dateinputs | Contains the KendoReact Date Inputs components that are used to select the date and time for an appointment. |
@progress/kendo-react-dropdowns | Contains the KendoReact Dropdowns, which allows users to choose from a predefined list of options. |
@progress/kendo-react-inputs | Contains the KendoReact Inputs, which the input of data, based on a specific and predefined format. |
@progress/kendo-drawing | Contains the Drawing library, which provides interactive vector graphics. |
@progress/kendo-react-buttons | Contains the KendoReact Buttons library, which provides buttons. |
@progress/kendo-react-treeview | Contains the KendoReact TreeView package that is used in the DropDowns. |
@progress/kendo-react-popup | Contains the KendoReact Popup components. |
@progress/kendo-svg-icons | Contains the KendoReact SVG icons. |
Suggested Links
- Setting Up Local Data Operations
- Applying Data Operations on the Server
- Editing Grid Data Records
- Using Locked Columns
- Exporting to PDF
- Styling the Grid
- API Reference of the Grid
- Virtual Classroom (Introductory Course Available to Trial and Commercial License Holders)
- Explore the Finance Portfolio Sample Application
- Explore the Coffee Warehouse Sample Application
- Explore the GitHub Issues Grid Sample Application