Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / Java

Building a Smart Data Table in React

4.50/5 (2 votes)
11 Jun 2021CPOL5 min read 5.3K  
Capabilities expected from a smart table and few open source alternatives
In this article, we'll discuss which capabilities are expected from a smart table, and assess a few open-source alternatives.

Introduction

Tables are one of the easiest ways to present data on web pages. Plain HTML tables can meet the basic data presentation needs, but trying to squeeze anything sophisticated from them will quickly make you frustrated.

This is when you need to make some important decisions about your application development path. You can start coding enhancements around old-fashioned HTML tables — at the risk of losing focus on your project — or you look at the existing products that are designed to solve your problems.

Today’s market offers dedicated smart table controls that handle the table part for you and provide additional features, including selection modes, sorting and column reordering.

Many companies use data tables to show complex reports, dashboards, financial data, sales results, and even interactive spreadsheets. High demand begot specialized supply, so tables are well represented in web component libraries.

In this article, we'll discuss which capabilities are expected from a smart table, assess a few open-source alternatives, and demonstrate how to create superior HTML smart data tables with GrapeCity's solution for the React JavaScript library. We are assuming that you have some web development experience and preferably familiarity with React.

Table Capabilities

There are some key features that people expect from a smart data table:

  • Data features

    • Load data from the various sources, including local files, databases, and APIs
    • Searching, filtering, and sorting options
    • Load and display of large datasets with pagination
    • Ability to import and export data
  • UI features

    • Showing and hiding columns
    • Inline editing
    • Responsiveness — built-in support for multiple devices
    • Resizable columns to accommodate long data points inside a column (multi-line comments)
    • Horizontal and vertical scroll support
    • Data validations and visualizations, such as sparklines

Modern frameworks have built-in implementations of some of these features. However, you have to code more advanced features yourself.

Open Source Frameworks

Created and maintained by Facebook, React is a massively popular open-source JavaScript library. Currently, it holds around 60% of the JavaScript framework market share. With such widespread adoption in the industry, it’s no wonder that many products have been created to serve applications built on React.

Here are some popular open-source smart data table libraries made for React:

These open-source projects have advantages and disadvantages. Depending on which feature you are looking for, some of these components are better than others.

Create a React App with React Data Grid

Let’s build a new Node-based, React application with React Data Grid, an open-source component that has a look-and-feel close to what we are trying to demonstrate.

Install Node.js. Then, using a command-line console, create a new Node React app:

npx create-react-app my-app  
cd my-app  
npm start 

Install the React Data Grid package. Open the package.json file and add these lines in the dependencies section:

JavaScript
"babel-loader": "^8.1.0",  
"react-data-grid": "5.0.1",  
"react-data-grid-addons": "5.0.4",  
"bootstrap": "^4.5.2"

Append the following lines after the browserslist section:

JavaScript
"devDependencies": {  
  "immutable": "^4.0.0-rc.12"  
}

To install the React Data Grid package and its dependencies, run the npm install command-line instruction:

npm install

Add a new data folder under the src folder, and create a new file named data.js. The user will use the data to populate our data grid:

JavaScript
export const recentSales = [  
  {  
    id: 1,  
    country: "Canada",  
    soldBy: "Bill",  
    client: "Cerberus Corp.",  
    description: "Prothean artifacts",  
    value: 6250,  
    itemCount: 50  
  },  
  {  
    id: 2,  
    country: "Canada",  
    soldBy: "Bill",  
    client: "Strickland Propane",  
    description: "Propane and propane accessories",  
    value: 2265,  
    itemCount: 20  
  },  
  {  
    id: 3,  
    country: "USA",  
    soldBy: "Ted",  
    client: "Dunder Mifflin",  
    description: "Assorted paper-making supplies",  
    value: 4700,  
    itemCount: 10  
  },  
  {  
    id: 4,  
    country: "USA",  
    soldBy: "Ted",  
    client: "Utopia Planitia Shipyards",  
    description: "Dilithium, duranium, assorted shipbuilding supplies",  
    value: 21750,  
    itemCount: 250  
  },  
  {  
    id: 5,  
    country: "USA",  
    soldBy: "Ted",  
    client: "Glengarry Estates",  
    description: "Desks, phones, coffee, steak knives, and one Cadillac",  
    value: 5000,  
    itemCount: 5  
  },  
  {  
    id: 6,  
    country: "Germany",  
    soldBy: "Angela",  
    client: "Wayne Enterprises",  
    description: "Suit armor and run-flat tires",  
    value: 35000,  
    itemCount: 25  
  },  
  {  
    id: 7,  
    country: "Germany",  
    soldBy: "Angela",  
    client: "Stark Industries",  
    description: "Armor and rocket fuel",  
    value: 25000,  
    itemCount: 10  
  },  
  {  
    id: 8,  
    country: "Germany",  
    soldBy: "Angela",  
    client: "Nakatomi Trading Corp.",  
    description: "Fire extinguishers and replacement windows",  
    value: 15000,  
    itemCount: 50  
  },  
  {  
    id: 9,  
    country: "UK",  
    soldBy: "Jill",  
    client: "Spaceley Sprockets",  
    description: "Anti-gravity propulsion units",  
    value: 25250,  
    itemCount: 50  
  },  
  {  
    id: 10,  
    country: "UK",  
    soldBy: "Jill",  
    client: "General Products",  
    description: "Ion engines",  
    value: 33200,  
    itemCount: 40  
  }  
];

Add a new components folder under the src folder, and create a new file named OpenSourceTable-Demo.js:

/my-app  
  /src  
    /components  
      OpenSourceTable-Demo.js

Open the OpenSourceTable-Demo.js file and add the following code. (Here, we import the ReactDataGrid component and declare the React state variables that will be used by the data grid as column definitions and the component’s data source):

JavaScript
import 'bootstrap/dist/css/bootstrap.min.css';  
import React, { useState } from 'react';  
import ReactDOM from "react-dom";  
import ReactDataGrid from "react-data-grid";  
import { recentSales } from "../data/data";

export const OpenSourceTableDemo = () => {

  const [columns, setColumns] = new useState([  
    { key: "id", name: "Id" },  
    { key: "country", name: "Country" },  
    { key: "soldBy", name: "Sold by" },  
    { key: "client", name: "Client" },  
    { key: "description", name: "Description" },  
    { key: "value", name: "Value" },  
    { key: "itemCount", name: "Item Count" }  
  ]);

  const [sales, setSales] = new useState(recentSales);  
}

Modify the OpenSourceTableDemo component so that it returns the HTML with the ReactDataGrid component:

HTML
return (  
  <div className="card main-panel">  
    <div className="card-header">  
      <h1>Open Source</h1>  
    </div>  
    <div className="card-body">  
    <h5>React Data Grid Demo</h5>  
      <p>  
        Building a Smart Data Table in React with React Data Grid  
      </p>           
      <div className="container-fluid">  
        <div className="row">  
            <ReactDataGrid  
                columns={columns}  
                rowGetter={i => sales[i]}  
                rowsCount={recentSales.length}  
              />  
        </div>  
      </div>  
    </div>  
  </div>);

Edit the App.js file and replace its contents with the lines below:

JavaScript
import React from 'react';  
import './App.css';  
import { OpenSourceTableDemo } from './components/OpenSourceTable-Demo.js'

function App() {  
  return (  
    <OpenSourceTableDemo/>  
  );  
}

export default App;

Now run the app:

npm start

Once the app is running, you’ll see the React Data Grid displaying the sales data:

Image 1

To show some of the component features, let’s start customizing our open-source data grid to support cell value updates, row sorting, and column reordering.

Implement Cell Value Update

Open the OpenSourceTable-Demo.js file and add the editable: true attribute to each of the grid column definitions:

JavaScript
{ key: "id", name: "Id", editable: true },  
{ key: "country", name: "Country", editable: true },  
{ key: "soldBy", name: "Sold by", editable: true },  
{ key: "client", name: "Client", editable: true },  
{ key: "description", name: "Description", editable: true },  
{ key: "value", name: "Value", editable: true },  
{ key: "itemCount", name: "Item Count", editable: true }

Add a new onGridRowsUpdated function to handle cell updates and update the underlying data source:

JavaScript
const onGridRowsUpdated = ({ fromRow, toRow, updated }) => {
  const s = sales.slice();
  for (let i = fromRow; i <= toRow; i++) {
    s[i] = { ...s[i], ...updated };
  }
  setSales(s);
};

Modify the ReactDataGrid component to add the enableCellSelect={true} attribute and an onGridRowsUpdated={onGridRowsUpdated} event handler:

JavaScript
<ReactDataGrid  
  columns={columns}  
  rowGetter={i => sales[i]}  
  rowsCount={recentSales.length}  
  enableCellSelect={true}  
  onGridRowsUpdated={onGridRowsUpdated}  
/>

These changes allow your React Data Grid to handle updates and persist them in the underlying data source:

Image 2

Implement Row Sorting

Open the OpenSourceTable-Demo.js file and add the sortable: true attribute to each column definition to enable column sortability:

JavaScript
{ key: "id", name: "Id", editable: true, sortable: true },  
{ key: "country", name: "Country", editable: true, sortable: true },  
{ key: "soldBy", name: "Sold by", editable: true, sortable: true },  
{ key: "client", name: "Client", editable: true, sortable: true },  
{ key: "description", name: "Description", editable: true, sortable: true },  
{ key: "value", name: "Value", editable: true, sortable: true },  
{ key: "itemCount", name: "Item Count", editable: true, sortable: true }

Implement the new sortRows function:

JavaScript
const sortRows = (initialRows, sortColumn, sortDirection) => rows => {
  const comparer = (a, b) => {
    if (sortDirection === "ASC") {
      return a[sortColumn] > b[sortColumn] ? 1 : -1;
    } else if (sortDirection === "DESC") {
      return a[sortColumn] < b[sortColumn] ? 1 : -1;
    }
  };
  return sortDirection === "NONE" ? initialRows : [...rows].sort(comparer);
};

Modify the ReactDataGrid component to implement the onGridSort event handler and reference the function we have just created:

JavaScript
<ReactDataGrid  
  columns={columns}  
  rowGetter={i => sales[i]}  
  rowsCount={recentSales.length}  
  enableCellSelect={true}  
  onGridRowsUpdated={onGridRowsUpdated}  
  onGridSort={(sortColumn, sortDirection) =>  
      setSales(sortRows(sales, sortColumn, sortDirection))  
  }  
/>

Go back to the web page and notice how the columns are now sortable:

Image 3

Implement Column Reordering

Open the OpenSourceTable-Demo.js file and add this declaration after the imports section:

JavaScript
const {  
  DraggableHeader: { DraggableContainer }  
} = require("react-data-grid-addons");

Add the draggable: true property to each column definition to enable column repositioning:

JavaScript
{ key: "id", name: "Id", editable: true, sortable: true, draggable: true },  
{ key: "country", name: "Country", editable: true, sortable: true, draggable: true },  
{ key: "soldBy", name: "Sold by", editable: true, sortable: true, draggable: true },  
{ key: "client", name: "Client", editable: true, sortable: true, draggable: true },  
{ key: "description", name: "Description", editable: true, sortable: true, draggable: true },  
{ key: "value", name: "Value", editable: true, sortable: true, draggable: true },  
{ key: "itemCount", name: "Item Count", editable: true, sortable: true, draggable: true }

Add the onHeaderDrop function to handle column drag-and-drop event:

JavaScript
const onHeaderDrop = (source, target) => {  
  var columnsCopy = columns.slice();  
  const columnSourceIndex = columns.findIndex(  
    i => i.key === source  
  );  
  const columnTargetIndex = columns.findIndex(  
    i => i.key === target  
  );

  columnsCopy.splice(  
    columnTargetIndex,  
    0,  
    columnsCopy.splice(columnSourceIndex, 1)[0]  
  );

  setColumns(columnsCopy.splice());  
  setColumns(columnsCopy);  
};

Wrap your existing ReactDataGrid component inside a new DraggableContainer component:

JavaScript
<DraggableContainer onHeaderDrop={onHeaderDrop}>
    <ReactDataGrid
          columns={columns}
          rowGetter={i => sales[i]}
          rowsCount={recentSales.length}
          enableCellSelect={true}
          onGridRowsUpdated={onGridRowsUpdated}
          onGridSort={(sortColumn, sortDirection) =>
            setSales(sortRows(sales, sortColumn, sortDirection))
          }
      />
</DraggableContainer>

Rerun the app and try moving the grid columns around:

Image 4

That looks pretty good, but it was a lot of work to implement those features. Now you're on the hook to maintain that code.

Wrapping Up

You can create and use React-based smart data tables in various ways. Some approaches require far more manual work than others, but you can’t tell that until you have already spent enough time trying to use them.

There’s plenty of free and open-source table libraries that might meet your everyday needs. We’ve seen how to implement one of them in this article.

History

  • 11th June, 2021: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)