Welcome back to our AG-Grid React Series! In this installment, we're diving deep into customizing the visual appearance of your grid rows based on their data. Dynamic row styling is a powerful feature that enhances readability, highlights critical information, and makes your grids more intuitive for users.
Whether you need to color-code rows based on status, flag outliers, or simply make certain data types stand out, AG-Grid provides robust mechanisms through its getRowStyle and getRowClass callbacks. Let's explore how to implement these effectively.
Why Dynamic Row Styling Matters
Imagine a financial report with thousands of transactions. Applying a red background to all transactions marked 'failed' or a green background to 'completed' ones instantly provides a visual summary, saving users from painstakingly reading each row's status column. This is the core benefit of dynamic row styling:
- Improved Readability: Differentiate data categories at a glance.
- Highlighting Critical Data: Draw attention to important information, such as overdue items or high-priority tasks.
- Enhanced User Experience: Make complex datasets easier to navigate and understand.
- Brand Consistency: Apply specific color schemes or styles that align with your application's design language.
Prerequisites
This post assumes you have a basic AG-Grid React setup running. If you're just starting, please refer to earlier posts in this series or the official AG-Grid documentation to get your foundational grid ready.
1. Styling Rows with getRowStyle
The getRowStyle callback allows you to apply inline CSS styles directly to a row. This function receives an object containing row information and should return a CSS style object.
How it Works:
- AG-Grid calls this function for every row in the grid.
- It receives a parameter object with properties like
data(the row's data),node(the row node object),rowIndex, etc. - You return an object where keys are CSS property names (camelCase) and values are their corresponding CSS values.
Example: Highlighting Rows Based on a Numeric Threshold
Let's say we have a grid displaying product inventory, and we want to highlight products with less than 10 units in stock with a light yellow background.
First, define your AgGridReact component:
import React, { useState, useMemo, useCallback } from 'react';
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';
const InventoryGrid = () => {
const [rowData] = useState([
{ product: 'Laptop', unitsInStock: 25, price: 1200 },
{ product: 'Mouse', unitsInStock: 8, price: 25 },
{ product: 'Keyboard', unitsInStock: 15, price: 75 },
{ product: 'Monitor', unitsInStock: 5, price: 300 },
{ product: 'Webcam', unitsInStock: 30, price: 50 },
]);
const [columnDefs] = useState([
{ field: 'product' },
{ field: 'unitsInStock' },
{ field: 'price' },
]);
// Callback to apply row styles
const getRowStyle = useCallback((params) => {
if (params.data && params.data.unitsInStock < 10) {
return { background: '#ffe0b2' }; // Light orange background
}
return null; // No specific style
}, []);
const defaultColDef = useMemo(() => ({
flex: 1,
minWidth: 100,
resizable: true,
}), []);
return (
<div className="ag-theme-alpine" style={{ height: 400, width: 600 }}>
<AgGridReact
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
getRowStyle={getRowStyle} // Apply the style callback
></AgGridReact>
</div>
);
};
export default InventoryGrid;
In this example, rows with unitsInStock less than 10 will have a light orange background.
2. Applying Dynamic Classes with getRowClass
While getRowStyle is great for simple, direct styling, getRowClass is generally preferred for its maintainability, reusability, and separation of concerns. It allows you to apply one or more CSS class names to a row based on your logic.
How it Works:
- Similar to
getRowStyle, this function is called for each row. - It receives the same parameter object with
data,node, etc. - It should return a string of class names (space-separated) or an array of class names.
- The actual styling is then defined in your global or component-specific CSS.
Example: Status-Based Row Classes
Consider a task list where tasks can be 'Pending', 'InProgress', or 'Completed'. We want to style rows differently based on their status.
First, define your CSS classes. You'd typically put this in a global CSS file or a module-specific one.
/* App.css or GridStyles.css */
.task-pending {
background-color: #fff3e0; /* Light orange */
color: #e65100;
}
.task-in-progress {
background-color: #e0f2f7; /* Light blue */
color: #01579b;
}
.task-completed {
background-color: #e8f5e9; /* Light green */
color: #2e7d32;
}
.task-high-priority {
font-weight: bold;
border-left: 5px solid #d32f2f; /* Red left border */
padding-left: 5px; /* Adjust padding for the border */
}
Now, integrate these classes using getRowClass in your React component:
import React, { useState, useMemo, useCallback } from 'react';
import { AgGridReact } from 'ag-grid-react';
import 'ag-grid-community/styles/ag-grid.css';
import 'ag-grid-community/styles/ag-theme-alpine.css';
import './GridStyles.css'; // Import your custom CSS
const TaskGrid = () => {
const [rowData] = useState([
{ task: 'Implement Feature A', status: 'InProgress', priority: 'High' },
{ task: 'Fix Bug X', status: 'Pending', priority: 'High' },
{ task: 'Write Documentation', status: 'Completed', priority: 'Medium' },
{ task: 'Review Pull Request', status: 'InProgress', priority: 'Low' },
{ task: 'Deploy to Production', status: 'Pending', priority: 'High' },
]);
const [columnDefs] = useState([
{ field: 'task' },
{ field: 'status' },
{ field: 'priority' },
]);
// Callback to apply row classes
const getRowClass = useCallback((params) => {
const classes = [];
if (params.data) {
switch (params.data.status) {
case 'Pending':
classes.push('task-pending');
break;
case 'InProgress':
classes.push('task-in-progress');
break;
case 'Completed':
classes.push('task-completed');
break;
default:
break;
}
if (params.data.priority === 'High') {
classes.push('task-high-priority');
}
}
return classes; // Return an array of class names
}, []);
const defaultColDef = useMemo(() => ({
flex: 1,
minWidth: 100,
resizable: true,
}), []);
return (
<div className="ag-theme-alpine" style={{ height: 400, width: 800 }}>
<AgGridReact
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
getRowClass={getRowClass} // Apply the class callback
></AgGridReact>
</div>
);
};
export default TaskGrid;
In this task grid, rows will dynamically receive classes based on their status and priority. Notice how we return an array of classes, allowing a row to have multiple visual cues (e.g., a 'Pending' task that is also 'High Priority').
Combining getRowStyle and getRowClass
It's entirely possible to use both getRowStyle and getRowClass on the same grid. getRowClass is often preferred for more complex and reusable styling logic, while getRowStyle can be handy for very specific, one-off inline styles that don't warrant a dedicated CSS class.
Keep in mind that CSS specificity rules apply. If a style defined inline by getRowStyle conflicts with a style from a class applied by getRowClass, the inline style will typically take precedence.
Best Practices for Dynamic Row Styling
-
Prefer
getRowClass: For complex or frequently changing styles, usinggetRowClassand external CSS is generally more maintainable. It keeps your styling logic separate from your component's JSX and makes it easier to manage themes. -
Keep Logic Concise: The functions for
getRowStyleandgetRowClassare called for every row. Keep the logic inside them as efficient as possible to avoid performance bottlenecks, especially with large datasets. -
Leverage
useCallback: Wrap yourgetRowStyleandgetRowClassfunctions inuseCallbackto prevent unnecessary re-creations on every render, which can lead to performance improvements and prevent re-rendering of AG-Grid internally. -
Clear CSS Naming: Use descriptive class names that clearly indicate their purpose (e.g.,
low-stock-row,vip-customer-row). - Specificity: Be mindful of CSS specificity when defining your classes to ensure your dynamic styles override or complement default AG-Grid styles as intended.
Conclusion
Dynamic row styling with AG-Grid React is an indispensable tool for creating user-friendly and informative data grids. By intelligently applying styles or classes based on your data, you can significantly improve the usability and aesthetic appeal of your applications.
Experiment with both getRowStyle and getRowClass to find the approach that best suits your specific styling needs and project structure. In the next part of our series, we'll explore even more ways to customize the look and feel of your AG-Grid components!