DEV Community

Michael Turner
Michael Turner

Posted on

Building Feature-Rich Data Tables with jQWidgets React Grid

jQWidgets React Grid is a comprehensive data grid component for React that provides enterprise-grade functionality including sorting, filtering, grouping, editing, and virtualization. It's part of the jQWidgets suite, offering a rich set of features for building complex data management interfaces. This guide walks through creating advanced, interactive data tables using jQWidgets React Grid, covering setup, configuration, and practical implementation patterns. This is part 8 of a series on using jQWidgets React Grid with React.

Prerequisites

Before you begin, ensure you have:

  • Node.js version 14.0 or higher
  • npm, yarn, or pnpm package manager
  • A React project (version 16.8 or higher) with hooks support
  • Basic understanding of React hooks (useState, useRef, useEffect)
  • Familiarity with JavaScript/TypeScript

Installation

Install jQWidgets React Grid package:

npm install jqwidgets-scripts
Enter fullscreen mode Exit fullscreen mode

Or with yarn:

yarn add jqwidgets-scripts
Enter fullscreen mode Exit fullscreen mode

Or with pnpm:

pnpm add jqwidgets-scripts
Enter fullscreen mode Exit fullscreen mode

Your package.json should include:

{
  "dependencies": {
    "jqwidgets-scripts": "^15.0.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}
Enter fullscreen mode Exit fullscreen mode

Project Setup

jQWidgets requires CSS and JavaScript files to be imported. Add them to your main application file:

// src/index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import 'jqwidgets-scripts/jqwidgets/styles/jqx.base.css';
import 'jqwidgets-scripts/jqwidgets/styles/jqx.material.css';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
Enter fullscreen mode Exit fullscreen mode

First Example / Basic Usage

Let's create a basic data grid component. Create src/DataGrid.jsx:

// src/DataGrid.jsx
import React, { useRef, useEffect } from 'react';
import 'jqwidgets-scripts/jqwidgets/styles/jqx.base.css';
import 'jqwidgets-scripts/jqwidgets/styles/jqx.material.css';

function DataGrid() {
  const gridRef = useRef(null);

  // Column definitions
  const columns = [
    { text: 'ID', datafield: 'id', width: 80 },
    { text: 'First Name', datafield: 'firstName', width: 150 },
    { text: 'Last Name', datafield: 'lastName', width: 150 },
    { text: 'Email', datafield: 'email', width: 200 },
    { text: 'Role', datafield: 'role', width: 120 }
  ];

  // Row data
  const source = {
    localdata: [
      { id: 1, firstName: 'John', lastName: 'Doe', email: 'john@example.com', role: 'Admin' },
      { id: 2, firstName: 'Jane', lastName: 'Smith', email: 'jane@example.com', role: 'User' },
      { id: 3, firstName: 'Bob', lastName: 'Johnson', email: 'bob@example.com', role: 'User' },
      { id: 4, firstName: 'Alice', lastName: 'Williams', email: 'alice@example.com', role: 'Admin' }
    ],
    datatype: 'array'
  };

  useEffect(() => {
    if (gridRef.current && window.jqx) {
      // Initialize the grid
      window.jqx(gridRef.current, {
        width: '100%',
        height: 400,
        source: source,
        columns: columns,
        sortable: true,
        filterable: true,
        pageable: true,
        pagesize: 10
      });
    }
  }, []);

  return (
    <div style={{ padding: '20px' }}>
      <h2>jQWidgets Data Grid</h2>
      <div ref={gridRef}></div>
    </div>
  );
}

export default DataGrid;
Enter fullscreen mode Exit fullscreen mode

For a more React-friendly approach using the React wrapper component:

// src/DataGrid.jsx
import React from 'react';
import JqxGrid from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxgrid';
import 'jqwidgets-scripts/jqwidgets/styles/jqx.base.css';
import 'jqwidgets-scripts/jqwidgets/styles/jqx.material.css';

function DataGrid() {
  const columns = [
    { text: 'ID', datafield: 'id', width: 80 },
    { text: 'First Name', datafield: 'firstName', width: 150 },
    { text: 'Last Name', datafield: 'lastName', width: 150 },
    { text: 'Email', datafield: 'email', width: 200 },
    { text: 'Role', datafield: 'role', width: 120 }
  ];

  const source = {
    localdata: [
      { id: 1, firstName: 'John', lastName: 'Doe', email: 'john@example.com', role: 'Admin' },
      { id: 2, firstName: 'Jane', lastName: 'Smith', email: 'jane@example.com', role: 'User' },
      { id: 3, firstName: 'Bob', lastName: 'Johnson', email: 'bob@example.com', role: 'User' },
      { id: 4, firstName: 'Alice', lastName: 'Williams', email: 'alice@example.com', role: 'Admin' }
    ],
    datatype: 'array'
  };

  return (
    <div style={{ padding: '20px' }}>
      <h2>jQWidgets Data Grid</h2>
      <JqxGrid
        width={'100%'}
        height={400}
        source={source}
        columns={columns}
        sortable={true}
        filterable={true}
        pageable={true}
        pagesize={10}
      />
    </div>
  );
}

export default DataGrid;
Enter fullscreen mode Exit fullscreen mode

Understanding the Basics

jQWidgets React Grid uses a configuration-based approach where:

  • columns: Array of column definition objects
  • source: Data source configuration with local data or remote URL
  • datafield: Maps to a property in your row data
  • text: Column header text
  • width: Column width in pixels

Key concepts:

  • Data Source: Can be local (array) or remote (URL/API)
  • Column Definitions: Define structure, behavior, and appearance
  • Features: Enable/disable features like sorting, filtering, pagination
  • Themes: Multiple built-in themes (material, dark, etc.)

Here's an example with editable cells and row selection:

// src/EditableGrid.jsx
import React, { useState } from 'react';
import JqxGrid from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxgrid';
import 'jqwidgets-scripts/jqwidgets/styles/jqx.base.css';
import 'jqwidgets-scripts/jqwidgets/styles/jqx.material.css';

function EditableGrid() {
  const [selectedRowIndex, setSelectedRowIndex] = useState(null);

  const columns = [
    { text: 'ID', datafield: 'id', width: 80, editable: false },
    { text: 'Name', datafield: 'name', width: 200, editable: true },
    { text: 'Email', datafield: 'email', width: 250, editable: true },
    { text: 'Role', datafield: 'role', width: 150, editable: true }
  ];

  const source = {
    localdata: [
      { id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin' },
      { id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User' },
      { id: 3, name: 'Bob Johnson', email: 'bob@example.com', role: 'User' }
    ],
    datatype: 'array'
  };

  const handleCellEndEdit = (event) => {
    console.log('Cell edited:', event.args);
    // Update your data source here
  };

  const handleRowSelect = (event) => {
    setSelectedRowIndex(event.args.rowindex);
    console.log('Row selected:', event.args.row);
  };

  return (
    <div style={{ padding: '20px' }}>
      <h2>Editable Data Grid</h2>
      {selectedRowIndex !== null && (
        <p>Selected row index: {selectedRowIndex}</p>
      )}
      <JqxGrid
        width={'100%'}
        height={400}
        source={source}
        columns={columns}
        editable={true}
        selectionmode={'singlerow'}
        onCellendedit={handleCellEndEdit}
        onRowselect={handleRowSelect}
        sortable={true}
        filterable={true}
      />
    </div>
  );
}

export default EditableGrid;
Enter fullscreen mode Exit fullscreen mode

Practical Example / Building Something Real

Let's build a comprehensive employee management table with advanced features:

// src/EmployeeManagement.jsx
import React, { useState, useRef } from 'react';
import JqxGrid from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxgrid';
import JqxButton from 'jqwidgets-scripts/jqwidgets-react-tsx/jqxbuttons';
import 'jqwidgets-scripts/jqwidgets/styles/jqx.base.css';
import 'jqwidgets-scripts/jqwidgets/styles/jqx.material.css';

function EmployeeManagement() {
  const gridRef = useRef(null);
  const [data, setData] = useState([
    { id: 1, name: 'Sarah Johnson', department: 'Engineering', salary: 95000, status: 'Active' },
    { id: 2, name: 'Michael Chen', department: 'Marketing', salary: 75000, status: 'Active' },
    { id: 3, name: 'Emily Davis', department: 'Sales', salary: 65000, status: 'Active' },
    { id: 4, name: 'David Wilson', department: 'Engineering', salary: 110000, status: 'Active' },
    { id: 5, name: 'Lisa Anderson', department: 'HR', salary: 70000, status: 'Active' }
  ]);

  const columns = [
    { 
      text: 'ID', 
      datafield: 'id', 
      width: 80,
      pinned: true
    },
    { 
      text: 'Name', 
      datafield: 'name', 
      width: 200,
      editable: true,
      sortable: true
    },
    { 
      text: 'Department', 
      datafield: 'department', 
      width: 150,
      editable: true,
      filtertype: 'checkedlist'
    },
    { 
      text: 'Salary', 
      datafield: 'salary', 
      width: 120,
      editable: true,
      cellsformat: 'c2',
      cellsalign: 'right',
      filtertype: 'number'
    },
    { 
      text: 'Status', 
      datafield: 'status', 
      width: 120,
      editable: true,
      columntype: 'dropdownlist',
      filtertype: 'checkedlist'
    }
  ];

  const source = {
    localdata: data,
    datatype: 'array',
    datafields: [
      { name: 'id', type: 'number' },
      { name: 'name', type: 'string' },
      { name: 'department', type: 'string' },
      { name: 'salary', type: 'number' },
      { name: 'status', type: 'string' }
    ]
  };

  const handleAddRow = () => {
    const newRow = {
      id: data.length + 1,
      name: 'New Employee',
      department: 'Engineering',
      salary: 50000,
      status: 'Active'
    };
    setData([...data, newRow]);
  };

  const handleDeleteRow = () => {
    if (gridRef.current) {
      const selectedRowIndex = gridRef.current.getselectedrowindex();
      if (selectedRowIndex >= 0) {
        const newData = data.filter((_, index) => index !== selectedRowIndex);
        setData(newData);
      }
    }
  };

  const handleExport = () => {
    if (gridRef.current) {
      gridRef.current.exportdata('csv', 'employees');
    }
  };

  const handleCellEndEdit = (event) => {
    const { rowindex, datafield, value } = event.args;
    const newData = [...data];
    newData[rowindex][datafield] = value;
    setData(newData);
  };

  return (
    <div style={{ padding: '20px' }}>
      <div style={{ marginBottom: '20px', display: 'flex', gap: '10px', alignItems: 'center' }}>
        <h2>Employee Management</h2>
        <JqxButton onClick={handleAddRow} width={100} height={30}>
          Add Row
        </JqxButton>
        <JqxButton onClick={handleDeleteRow} width={100} height={30}>
          Delete Row
        </JqxButton>
        <JqxButton onClick={handleExport} width={100} height={30}>
          Export CSV
        </JqxButton>
      </div>
      <JqxGrid
        ref={gridRef}
        width={'100%'}
        height={500}
        source={source}
        columns={columns}
        editable={true}
        selectionmode={'singlerow'}
        sortable={true}
        filterable={true}
        showfilterrow={true}
        pageable={true}
        pagesize={10}
        groupable={true}
        onCellendedit={handleCellEndEdit}
        theme={'material'}
      />
    </div>
  );
}

export default EmployeeManagement;
Enter fullscreen mode Exit fullscreen mode

This example demonstrates:

  • Editable cells with different editor types
  • Row selection and deletion
  • Filtering with different filter types
  • Sorting and grouping
  • Pagination
  • Export functionality
  • Pinned columns
  • Custom cell formatting (currency for salary)
  • Dropdown editors for status field

Common Issues / Troubleshooting

  1. Grid not rendering: Ensure you've imported both CSS files (jqx.base.css and a theme CSS like jqx.material.css). Also verify that jQWidgets scripts are loaded.

  2. Data not displaying: Check that your source object has the correct structure with localdata array and datatype: 'array'. Verify that datafields match your column datafield values.

  3. Editing not working: Set editable: true in your grid configuration and ensure individual columns have editable: true if you want specific columns editable.

  4. Filtering not working: Enable filterable: true and showfilterrow: true in your grid configuration. Set appropriate filtertype in column definitions.

  5. Performance issues: For large datasets, consider using remote data source with server-side pagination instead of loading all data at once.

Next Steps

Now that you understand jQWidgets React Grid:

  • Explore advanced features like grouping, aggregation, and pivoting
  • Implement custom cell renderers and editors
  • Add server-side data loading with remote data source
  • Learn about column resizing, reordering, and pinning
  • Explore different themes and customization options
  • Add export functionality (Excel, PDF, CSV)
  • Check the official documentation: https://www.jqwidgets.com/react/react-grid/
  • Look for part 9 of this series for more advanced topics

Summary

You've learned how to set up jQWidgets React Grid and create feature-rich data tables with sorting, filtering, editing, and pagination. The library provides comprehensive functionality for building enterprise-grade data management interfaces with excellent performance and extensive customization options.

Top comments (0)