AG Grid is a powerful, feature-rich data grid library for React that provides enterprise-grade functionality including sorting, filtering, pagination, cell editing, and much more. It's designed to handle large datasets efficiently while maintaining excellent performance. This guide walks through creating advanced, interactive data tables using AG Grid with React, covering setup, configuration, and practical implementation patterns. This is part 2 of a series on using AG Grid with React.
Prerequisites
Before you begin, ensure you have:
- Node.js version 16.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, useCallback)
- Familiarity with JavaScript/TypeScript
Installation
Install AG Grid React package and its community styles:
npm install ag-grid-react ag-grid-community
Or with yarn:
yarn add ag-grid-react ag-grid-community
Or with pnpm:
pnpm add ag-grid-react ag-grid-community
Your package.json should now include:
{
"dependencies": {
"ag-grid-react": "^31.0.0",
"ag-grid-community": "^31.0.0",
"react": "^18.0.0",
"react-dom": "^18.0.0"
}
}
Project Setup
AG Grid requires CSS styles to be imported. Add the grid styles and a theme to your main application file:
// src/index.js or src/main.jsx
import React from 'react';
import ReactDOM from 'react-dom/client';
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-quartz.css';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Available themes include:
-
ag-theme-quartz(modern, default) -
ag-theme-alpine(classic) -
ag-theme-balham(dark)
First Example / Basic Usage
Let's create a basic data grid component. Create src/DataGrid.jsx:
// src/DataGrid.jsx
import React, { useState } from 'react';
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-quartz.css';
function DataGrid() {
// Row data - the data to be displayed
const [rowData] = useState([
{ make: 'Tesla', model: 'Model Y', price: 64950, electric: true },
{ make: 'Ford', model: 'F-Series', price: 33850, electric: false },
{ make: 'Toyota', model: 'Corolla', price: 29600, electric: false },
{ make: 'BMW', model: '3 Series', price: 41500, electric: false },
{ make: 'Nissan', model: 'Leaf', price: 28140, electric: true }
]);
// Column definitions - defines the columns structure
const [columnDefs] = useState([
{ field: 'make', sortable: true, filter: true },
{ field: 'model', sortable: true, filter: true },
{
field: 'price',
sortable: true,
filter: 'agNumberColumnFilter',
valueFormatter: params => '$' + params.value.toLocaleString()
},
{
field: 'electric',
cellRenderer: params => params.value ? '⚡ Yes' : 'No'
}
]);
// Default column properties applied to all columns
const defaultColDef = {
sortable: true,
filter: true,
flex: 1,
resizable: true
};
return (
<div className="ag-theme-quartz" style={{ height: 500, width: '100%' }}>
<AgGridReact
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
pagination={true}
paginationPageSize={10}
/>
</div>
);
}
export default DataGrid;
Update your App.jsx:
// src/App.jsx
import React from 'react';
import DataGrid from './DataGrid';
import './App.css';
function App() {
return (
<div className="App">
<h1>AG Grid Data Table</h1>
<DataGrid />
</div>
);
}
export default App;
This creates a fully functional data grid with sorting, filtering, and pagination. Users can click column headers to sort, use the filter icons, and navigate through pages.
Understanding the Basics
AG Grid uses a declarative approach where you define:
- rowData: An array of objects representing table rows
- columnDefs: An array defining column structure, properties, and behavior
- defaultColDef: Default properties applied to all columns
Key concepts:
- Field: Maps to a property in your row data object
- Cell Renderer: Custom component or function to render cell content
- Value Formatter: Formats the displayed value without changing the data
- Filters: Built-in filters (text, number, date) or custom filters
- Sorting: Enable sorting per column or globally
Here's an example with editable cells and row selection:
// src/EditableGrid.jsx
import React, { useState, useCallback } from 'react';
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-quartz.css';
function EditableGrid() {
const [rowData, setRowData] = useState([
{ id: 1, name: 'John Doe', email: 'john@example.com', age: 28 },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', age: 32 },
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', age: 45 }
]);
const [columnDefs] = useState([
{
field: 'id',
checkboxSelection: true,
headerCheckboxSelection: true,
width: 100
},
{ field: 'name', editable: true, sortable: true },
{ field: 'email', editable: true, filter: 'agTextColumnFilter' },
{
field: 'age',
editable: true,
filter: 'agNumberColumnFilter',
cellEditor: 'agNumberCellEditor'
}
]);
const defaultColDef = {
flex: 1,
sortable: true,
filter: true
};
const onCellValueChanged = useCallback((event) => {
console.log('Cell value changed:', event.data);
// Update your state or sync with backend
const updatedData = rowData.map(row =>
row.id === event.data.id ? event.data : row
);
setRowData(updatedData);
}, [rowData]);
return (
<div className="ag-theme-quartz" style={{ height: 400, width: '100%' }}>
<AgGridReact
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
rowSelection="multiple"
onCellValueChanged={onCellValueChanged}
animateRows={true}
/>
</div>
);
}
export default EditableGrid;
Practical Example / Building Something Real
Let's build a comprehensive employee management table with advanced features:
// src/EmployeeTable.jsx
import React, { useState, useRef, useCallback } from 'react';
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-quartz.css';
function EmployeeTable() {
const gridRef = useRef();
const [rowData] = useState([
{
id: 1,
name: 'Sarah Johnson',
department: 'Engineering',
salary: 95000,
startDate: '2020-01-15',
status: 'Active'
},
{
id: 2,
name: 'Michael Chen',
department: 'Marketing',
salary: 75000,
startDate: '2019-06-20',
status: 'Active'
},
{
id: 3,
name: 'Emily Davis',
department: 'Sales',
salary: 65000,
startDate: '2021-03-10',
status: 'Active'
},
{
id: 4,
name: 'David Wilson',
department: 'Engineering',
salary: 110000,
startDate: '2018-09-05',
status: 'Active'
},
{
id: 5,
name: 'Lisa Anderson',
department: 'HR',
salary: 70000,
startDate: '2022-01-08',
status: 'Active'
}
]);
const [columnDefs] = useState([
{
field: 'id',
headerName: 'ID',
width: 80,
checkboxSelection: true,
headerCheckboxSelection: true
},
{
field: 'name',
headerName: 'Employee Name',
sortable: true,
filter: 'agTextColumnFilter',
editable: true
},
{
field: 'department',
headerName: 'Department',
sortable: true,
filter: 'agSetColumnFilter',
editable: true,
cellEditor: 'agSelectCellEditor',
cellEditorParams: {
values: ['Engineering', 'Marketing', 'Sales', 'HR', 'Finance']
}
},
{
field: 'salary',
headerName: 'Salary',
sortable: true,
filter: 'agNumberColumnFilter',
editable: true,
cellEditor: 'agNumberCellEditor',
valueFormatter: params => '$' + params.value.toLocaleString(),
cellStyle: params => {
if (params.value > 100000) {
return { backgroundColor: '#d4edda' };
}
return null;
}
},
{
field: 'startDate',
headerName: 'Start Date',
sortable: true,
filter: 'agDateColumnFilter',
valueFormatter: params => {
const date = new Date(params.value);
return date.toLocaleDateString('en-US');
}
},
{
field: 'status',
headerName: 'Status',
sortable: true,
filter: 'agSetColumnFilter',
cellRenderer: params => {
const status = params.value;
const color = status === 'Active' ? 'green' : 'red';
return `<span style="color: ${color}; font-weight: bold;">${status}</span>`;
}
}
]);
const defaultColDef = {
flex: 1,
sortable: true,
filter: true,
resizable: true
};
const onGridReady = useCallback((params) => {
console.log('Grid ready with', params.api.getDisplayedRowCount(), 'rows');
// Auto-size columns to fit content
params.api.sizeColumnsToFit();
}, []);
const onSelectionChanged = useCallback(() => {
const selectedRows = gridRef.current.api.getSelectedRows();
console.log('Selected rows:', selectedRows);
}, []);
const onExportClick = useCallback(() => {
gridRef.current.api.exportDataAsCsv({
fileName: 'employees.csv',
onlySelected: false
});
}, []);
const onFilterChanged = useCallback(() => {
const rowCount = gridRef.current.api.getDisplayedRowCount();
console.log('Filtered rows:', rowCount);
}, []);
return (
<div style={{ padding: '20px' }}>
<div style={{ marginBottom: '20px' }}>
<h2>Employee Management Table</h2>
<button
onClick={onExportClick}
style={{
padding: '10px 20px',
backgroundColor: '#007bff',
color: 'white',
border: 'none',
borderRadius: '4px',
cursor: 'pointer'
}}
>
Export to CSV
</button>
</div>
<div
className="ag-theme-quartz"
style={{ height: 600, width: '100%' }}
>
<AgGridReact
ref={gridRef}
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
rowSelection="multiple"
pagination={true}
paginationPageSize={10}
animateRows={true}
onGridReady={onGridReady}
onSelectionChanged={onSelectionChanged}
onFilterChanged={onFilterChanged}
/>
</div>
</div>
);
}
export default EmployeeTable;
This example demonstrates:
- Multi-row selection with checkboxes
- Editable cells with validation
- Custom cell renderers and formatters
- Conditional cell styling
- Export functionality
- Advanced filtering (text, number, date, set filters)
- Event handling for grid interactions
Common Issues / Troubleshooting
Grid not displaying: Ensure you've imported both CSS files (
ag-grid.cssand a theme CSS). The container div must have an explicit height.Styling issues: Make sure you're applying the theme class (
ag-theme-quartz) to the container div, not just importing the CSS.Performance with large datasets: For datasets with 1000+ rows, consider enabling virtualization (enabled by default) or using the server-side row model for better performance.
TypeScript errors: If using TypeScript, install
@types/reactand ensure your column definitions match theColDeftype fromag-grid-community.Cell editing not working: Verify that
editable: trueis set in column definitions and that you're handlingonCellValueChangedevents if needed.
Next Steps
Now that you understand the basics of AG Grid:
- Explore advanced features like custom cell renderers, cell editors, and value getters
- Learn about server-side row model for handling large datasets
- Implement custom filters and sorting logic
- Add row grouping and aggregation features
- Explore the enterprise features (if using AG Grid Enterprise)
- Check the official documentation: https://www.ag-grid.com/react-data-grid/
- Look for part 3 of this series for more advanced topics
Summary
You've learned how to set up AG Grid in React and create feature-rich data tables with sorting, filtering, pagination, and editing capabilities. AG Grid provides a robust foundation for building enterprise-grade data management interfaces with excellent performance and extensive customization options.
Top comments (0)