Blog
Building DataGrids with Cube and DevExtreme
This article is a step-by-step guide for using Cube and DevExtreme together for building data-driven web applications. We will walk through the process of displaying and visualizing data with the DevExtreme Data Grid components. We will start from scratch and build a minimalistic application, without using any server-side application. The application will use only what is needed for the demonstration, right here and right now.
Table of Contents
Overview of DataGrids
DataGrids are an extremely powerful data analytics tool that are more useful than traditional graphical dashboards in some situations.


DataGrids are more flexible than dashboards because they allow users to create customized views of the data. Users can choose which columns to display, filter the data, sort it in different ways, and group it as needed.


While dashboards usually provide a high-level overview of the data that can be useful in certain applications, DataGrids allow users to view the details of individual data points.

Last but not least, DataGrids provide users with an Excel-style experience, making data analytics significantly easier for people familiar with Excel

There are several tools for DataGrids available. There are proprietary ones, such as AG Grid and Handsontable, and even some open-source options such as React Table, Grid.js, Tabulator, DataTables, React-Data-Grid just to name a few.

However, in this article we’ll work with DevExtreme DataGrids, as this solution provides reach functionality and has a flexible licensing policy.
What is DevExtreme?
DevExtreme is a popular UI library for building data-intensive web applications.


A DataGrid is a user interface element that enables the display of data originating from local or remote sources in a grid format. This user interface component provides fundamental functionalities, including sorting, grouping, and filtering, as well as more sophisticated features such as state preservation, client-side export, master-detail interface, and numerous additional capabilities.
Overall, DevExtreme provides a comprehensive set of UI components and built-in data handling, making it a great choice for building data-intensive web applications.


While Material UI, Ant Design, Semantic UI, Bootstrap, and Foundation are all popular UI libraries, DevExtreme has established itself as a top contender in terms of functionality, especially for developers working with large data sets and complex logic.
Why use Cube and DevExtreme together?
Seamless integration: DevExtreme and Cube integrate seamlessly, allowing you to easily connect your Cube data source to DevExtreme components. This integration simplifies the process of fetching, displaying, and manipulating data in your application, and reduces the amount of boilerplate code you need to write.


Scalability: Both DevExtreme and Cube are designed with scalability in mind. Cube provides a flexible and scalable data layer, capable of handling large datasets and complex queries efficiently. This, combined with DevExtreme's high-performance UI components, allows you to build applications that can handle a growing amount of data and users with ease.


Customization: DevExtreme components are highly customizable, allowing you to match the look and feel of your application to your specific requirements. Cube, on the other hand, offers a powerful query language and API that can be tailored to your data needs, giving you full control over the data you retrieve and display in your application.


In addition, deploying the project and configuring the basic setup takes very little time, which I will demonstrate later on.
Initiating Cube service
There are two methods for deploying Cube: Cube Cloud and Docker. We will be using Docker for this demonstration and connecting to a sample ecom database.
1. First, create a docker-compose.yml file in the root directory of your project with the following
version: ‘2.2'

services:
cube:
image: cubejs/cube:latest
ports:
- 4000:4000
- 15432:15432
environment:
- CUBEJS_DEV_MODE=true
volumes:
- .:/cube/conf
Successfilly copied!
To start the Cube service, run the following command in your terminal:
docker-compose up -d
Now that the Cube service is running, let's connect to the sample ecom database.
  1. Open your web browser and navigate to http://localhost:4000 to access the Cube Playground.
  2. You should see a "Connect to Your Database" screen. Select "PostgreSQL" as your database type.
  3. Enter the following credentials provided for the sample ecom database:
Host: demo-db.cube.dev
Port: 5432
Database: ecom
Username: cube
Password: 12345
4. Once you've connected to the database in Cube Playground, go to the "Schema" tab. Find the "Users" table, select it and click on "Generate Schema”Here's the link to the official Cube documentation on deploying Cube with Docker: https://cube.dev/docs/getting-started/core/overview. To see an example of the resulting repository structure after running the Docker container and generating the Users schema, check out the https://github.com/DenisSeverinov/cubejs-service repository.
As you can see, deploying Cube with Docker is quite simple and straightforward!
Creating a Client Application?
For our application, we will be using pnpm and Vite.

Here's an overview for initializing the client application that uses only the essential components for a minimal demonstration of Cube and DevExtreme working together. The ready-to-use example repository is available at https://github.com/DenisSeverinov/devextreme-cubejs-DataGrid-reports
  1. Create the project: Run `pnpm create vite my-app --template react-ts`.
  2. Install Cube and DevExtreme: Run `pnpm add @cubejs-client/core @cubejs-client/react devextreme devextreme-react`.
  3. Modify the App component:
import { CubeProvider } from "@cubejs-client/react";
import cubejs from '@cubejs-client/core';
import "devextreme/dist/css/dx.light.css";
import { TableUsers } from "./components/TableUsers";

export const cubejsApi = cubejs({
apiUrl: 'http://localhost:4000/cubejs-api/v1',
});

const App = () => {
return (
<CubeProvider cubejsApi={cubejsApi}>
<TableUsers />
</CubeProvider>
);
};
export default App;
Successfilly copied!
4. Create the TableUsers component:
import { TableColumn } from "@cubejs-client/core";
import { useCubeQuery } from "@cubejs-client/react";
import DataGrid, { Column } from "devextreme-react/data-grid";

const getColumns = (columns: TableColumn[]) =>
columns.map(({ key, title }) => (
<Column
key={key}
caption={title}
calculateCellValue={(rowData: Record<string, string>) =>
rowData[key]
}
/>
));

export const TableUsers = () => {
const { resultSet, isLoading, error } = useCubeQuery({
measures: [],
dimensions: [
"Users.city",
"Users.company",
"Users.gender",
"Users.firstName",
"Users.lastName",
],
});

if (isLoading) {
return <div>Loading...</div>;
}

if (error) {
return <div>Error: {error.message}</div>;
}

if (!resultSet) {
return null;
}

const dataSource = resultSet.tablePivot();

const columns = resultSet.tableColumns();

return <DataGrid dataSource={dataSource}>{getColumns(columns)}</DataGrid>;
};
Successfilly copied!
5. Start the project: Run `pnpm dev`.
That's it! You've quickly and easily set up a start configuration. Further configurations will depend on your specific requirements.

You can also enable server-side DataGrid management for more optimized and efficient handling of large data volumes using Cube, eliminating the need for a separate backend.
Basic customization
Let's add a datafield to columns. The dataField property is required to connect columns to the correct fields in the data source, allowing functions such as sorting, filtering, and grouping to work seamlessly.
const getColumns = (columns: TableColumn[]) =>
columns.map(({ key, title }) => (
<Column
key={key}
caption={title}
dataField={key}
calculateCellValue={(rowData: Record<string, string>) => rowData[key]}
/>
));
Successfilly copied!
Also, in our example, we have added several essential properties to the DataGrid configuration:
  1. FilterRow - The filter row allows a user to filter data by values of individual columns.
  2. GroupPanel - Data in DataGrid can be grouped by one column or by several. Once a column is used for grouping, it is added to the group panel.
  3. Export - A user can click the Export button to save an Excel or PDF file with the exported data. Data types, sort, filter, and group settings are maintained.
Moreover, we've included allowColumnResizing, which allows users to resize columns by dragging their edges.
return (
<DataGrid dataSource={dataSource} allowColumnResizing>
<FilterRow visible />
<GroupPanel visible />
<Export enabled />
{getColumns(columns)}
</DataGrid>
);
Successfilly copied!
For this demonstration, I expanded the “Users Company” column in width, grouped the data by “Users City”, and filtered by "female" in the “Users Genders” column.
Now our DataGrid looks like this
Further customization
Now, let's add a few more properties to demonstrate additional features of the DevExtreme DataGrid component:

  1. FilterPanel - The Filter Panel is a UI element that displays the combined filter applied to the data grid.
  2. HeaderFilter - A header filter allows users to filter field values by including or excluding them from the applied filter.
  3. SearchPanel - This property adds a search panel for filtering data based on user input.
  4. Paging - This setting configures paging
  5. Summary - Summary display modes are post-processing functions that allow you to perform additional calculations on each summary value and take into account neighboring summary values. You can use summary display modes to present pivot data from different perspectives.
For this demonstration, I have set the default paging size to 10, displayed the search panel with a width of 300 pixels, and configured the DataGrid to save its state in the browser's localStorage to maintain the grid state even after the page refreshes. Additionally, I have included a summary feature to calculate the total number of companies within the DataGrid.
return (
<datagrid dataSource={dataSource} allowColumnResizing>
<FilterRow visible />
<FilterPanel visible />
<HeaderFilter visible />
<SearchPanel visible width={300} placeholder="Search" />
<Paging defaultPageSize={10} />
<StateStoring enabled type="localStorage" storageKey="DataGrid-options" />
<GroupPanel visible />
<Export enabled />
{getColumns(columns)}
<Summary>
<TotalItem column="Users Company" summaryType="count" />
</Summary>
</DataGrid>
);
Successfilly copied!
Now our DataGrid looks like this
And these are hardly all the capabilities DataGrids.
Wrapping up
In summary, utilizing Cube and DevExtreme together presents a robust and adaptable framework for managing and displaying data in an attractive and efficient manner.

Cube excels in providing a versatile and dynamic approach to data handling, simplifying tasks such as data querying, aggregation, and optimization. With Cube, it's possible to effortlessly merge multiple data sources, implement caching, and optimize query execution without requiring an additional backend layer.

DevExtreme DataGrids offer a wide array of features that enable developers to showcase data in an intuitive and visually appealing format. This empowers developers to design interactive and sophisticated data presentations with minimal effort when combined with Cube's flexible data manipulation capabilities.
About Us
Samgau is a software development company with over 200 talented engineers. One of our focus areas is data visualization. At our company, we take pride in our proven track record of successfully delivering data visualization projects that drive impactful results for our clients. Nothing gives us more satisfaction than providing our customers with solutions built upon Cube as a backend, delivering a versatile and resilient data platform for their needs.
15.11.2023
Transform Your Data into Vision.
2024 All rights reserved.
Signup for our newsletter (no more than once per month, we promise)