Theming and Styling AG-Grid in React
AG-Grid is an incredibly powerful and feature-rich data grid component for React applications. While its out-of-the-box functionality is impressive, its default appearance might not always align with your application's branding or user experience goals. This guide, part of our AG-Grid-React series, dives deep into how you can theme and style AG-Grid to perfectly integrate it into your UI.
Effective theming and styling are crucial for:
- Brand Consistency: Ensuring the grid seamlessly matches your application's visual identity.
- Enhanced User Experience: Improving readability, navigation, and overall user interaction.
- Accessibility: Customizing colors and fonts to meet accessibility standards.
- Differentiation: Giving your application a unique and polished look.
AG-Grid's Theming Philosophy
AG-Grid offers a flexible approach to styling, catering to different levels of customization:
- Built-in Themes: A set of ready-to-use themes that provide a quick way to change the grid's overall look.
- CSS Custom Properties (Variables): The easiest way to make quick, targeted adjustments to built-in themes without writing extensive CSS.
- SCSS Variables: For more in-depth customization, AG-Grid exposes a comprehensive set of SCSS variables, allowing you to build entirely new themes based on its underlying structure.
- Direct CSS Overrides: For highly specific styling of individual elements, you can target AG-Grid's CSS classes directly.
- Component-Specific Styling: Using properties like
cellClass,rowClassRules, orheaderClassto apply styles conditionally or to specific parts of the grid.
Applying Built-in Themes
The simplest way to theme your AG-Grid is by using one of its many built-in themes. These themes are provided as CSS files that you import into your project.
First, install the AG-Grid styles:
npm install --save ag-grid-community ag-grid-react
Then, import the desired theme's CSS file into your main stylesheet (e.g., App.css or a global SCSS file) or directly into your component's JavaScript file.
/* styles.css or App.css */
@import '~ag-grid-community/styles/ag-grid.css'; /* Core grid CSS */
@import '~ag-grid-community/styles/ag-theme-alpine.css'; /* Alpine theme */
/* Or another theme, e.g., ag-theme-balham.css, ag-theme-quartz.css, ag-theme-material.css */
Next, apply the theme class to the container div of your AgGridReact component:
import React, { useState, useRef, useEffect, useMemo, useCallback } from 'react';
import { AgGridReact } from 'ag-grid-react';
// Import AG-Grid styles (if not imported globally)
// import 'ag-grid-community/styles/ag-grid.css';
// import 'ag-grid-community/styles/ag-theme-alpine.css'; // The theme itself
const MyGridComponent = () => {
const gridRef = useRef();
const [rowData] = useState([
{ make: 'Toyota', model: 'Celica', price: 35000 },
{ make: 'Ford', model: 'Mondeo', price: 32000 },
{ make: 'Porsche', model: 'Boxster', price: 72000 }
]);
const [columnDefs] = useState([
{ field: 'make' },
{ field: 'model' },
{ field: 'price' }
]);
const defaultColDef = useMemo(() => ({
flex: 1,
minWidth: 100,
resizable: true,
sortable: true,
filter: true,
}), []);
return (
<div className="ag-theme-alpine" style={{ height: 400, width: 600 }}>
<AgGridReact
ref={gridRef}
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
animateRows={true}
/>
</div>
);
};
export default MyGridComponent;
In the example above, ag-theme-alpine is the class that applies the Alpine theme to the grid. Simply change this class name to explore other built-in themes like ag-theme-balham, ag-theme-quartz, or ag-theme-material.
Customizing Built-in Themes with CSS Variables
Even with built-in themes, you'll often want to tweak colors, borders, or fonts to match your application's palette more precisely. AG-Grid makes this incredibly easy using CSS Custom Properties (variables).
Each AG-Grid theme exposes a set of CSS variables that you can override. These variables typically start with --ag-. By defining these variables in a scope that targets your grid, you can change aspects of the theme without needing to write complex SCSS.
Here's how you might override some common variables for the ag-theme-alpine theme:
/* MyGridComponent.css */
.ag-theme-alpine-custom {
/* Base colors */
--ag-foreground-color: #333;
--ag-background-color: #f8f8f8;
--ag-header-background-color: #e6f7ff; /* Light blue header */
--ag-border-color: #ddd;
/* Text and link colors */
--ag-range-selection-border-color: #007bff;
--ag-row-hover-color: #e9ecef; /* Lighter hover effect */
--ag-selected-row-background-color: #007bff20; /* Light blue selection */
/* Font properties */
--ag-font-family: 'Roboto', sans-serif;
--ag-font-size: 14px;
}
And then apply this custom class to your grid container:
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-alpine.css'; // Base theme
import './MyGridComponent.css'; // Your custom styles
const MyGridComponent = () => {
// ... (same as before)
return (
<div className="ag-theme-alpine ag-theme-alpine-custom" style={{ height: 400, width: 600 }}>
<AgGridReact
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
animateRows={true}
/>
</div>
);
};
export default MyGridComponent;
By adding ag-theme-alpine-custom alongside ag-theme-alpine, your custom variables will override the defaults provided by the Alpine theme, thanks to CSS specificity.
Creating a Completely Custom Theme with SCSS
For ultimate control, AG-Grid allows you to build a theme from the ground up using its SCSS mixins and variables. This is the approach for creating a theme that perfectly matches a unique design system.
First, ensure you have a SCSS preprocessor set up in your React project (e.g., using Create React App with node-sass or Vite with default SCSS support).
Create an SCSS file (e.g., ./src/themes/my-custom-theme.scss):
@use "sass:map";
@import '~ag-grid-community/styles/ag-grid.scss';
// Define your custom theme variables here
// These variables control colors, spacing, borders, etc.
// A full list can be found in the AG-Grid documentation.
$ag-grid-variables: (
font-family: 'Open Sans', sans-serif,
foreground-color: #212529,
background-color: #f5f5f5,
border-color: #dee2e6,
header-background-color: #6c757d, // Darker header
header-foreground-color: #ffffff, // White text for header
row-hover-color: #e9ecef,
row-alt-background-color: #f8f9fa,
range-selection-background-color: rgba(108, 117, 125, 0.1),
selected-row-background-color: rgba(108, 117, 125, 0.2),
grid-size: 8px, // Controls spacing and padding
border-radius: 4px,
focus-color: #007bff,
);
// Create a custom theme mixin using ag-grid's 'ag-theme' mixin
@mixin ag-theme-my-custom-theme($ag-grid-variables...) {
@include ag-theme(
(
// Merge default AG-Grid variables with your custom ones
// You can also override individual variables here
),
$ag-grid-variables... // Pass your custom variables
);
}
// Apply the theme to a custom CSS class
.ag-theme-my-custom-theme {
@include ag-theme-my-custom-theme($ag-grid-variables);
}
Then, import this SCSS file into your main application (e.g., App.js or index.js) or a global stylesheet that your components use:
/* App.js or index.js */
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import './themes/my-custom-theme.scss'; // Import your custom theme SCSS
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Finally, apply your custom theme class to your grid container:
import React, { useState } from 'react';
import { AgGridReact } from 'ag-grid-react';
// Do not import ag-grid-community/styles/ag-theme-alpine.css if you're building a custom theme
const MyGridComponent = () => {
// ... (same as before)
return (
<div className="ag-theme-my-custom-theme" style={{ height: 400, width: 600 }}>
<AgGridReact
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
animateRows={true}
/>
</div>
);
};
export default MyGridComponent;
This approach gives you granular control over every visual aspect of the grid.
Cell Styling
Beyond overall themes, you often need to style individual cells based on their content or specific conditions. AG-Grid offers several ways to achieve this:
cellClass: A string or array of strings of CSS class names to apply to cells in a column.cellClassRules: An object mapping CSS class names to functions that returntrueorfalsebased on cell data.cellStyle: An object of CSS styles or a function returning such an object, applied directly to the cell element.
Example using cellClassRules to highlight prices:
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-alpine.css';
import './MyGridComponent.css'; // For custom cell classes
const MyGridComponent = () => {
const [rowData] = useState([
{ make: 'Toyota', model: 'Celica', price: 35000 },
{ make: 'Ford', model: 'Mondeo', price: 32000 },
{ make: 'Porsche', model: 'Boxster', price: 72000 }
]);
const [columnDefs] = useState([
{ field: 'make' },
{ field: 'model' },
{
field: 'price',
cellClassRules: {
'rag-green': params => params.value > 60000,
'rag-amber': params => params.value >= 30000 && params.value <= 60000,
'rag-red': params => params.value < 30000,
}
}
]);
const defaultColDef = useMemo(() => ({
flex: 1,
minWidth: 100,
resizable: true,
sortable: true,
filter: true,
}), []);
return (
<div className="ag-theme-alpine" style={{ height: 400, width: 600 }}>
<AgGridReact
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
animateRows={true}
/>
</div>
);
};
export default MyGridComponent;
And the corresponding CSS for the classes:
/* MyGridComponent.css */
.rag-green {
background-color: #d4edda;
color: #155724;
}
.rag-amber {
background-color: #fff3cd;
color: #856404;
}
.rag-red {
background-color: #f8d7da;
color: #721c24;
}
Row Styling
Similar to cells, you can style entire rows based on data conditions or other logic:
rowClassRules: An object mapping CSS class names to functions that returntrueorfalsebased on row data.getRowStyle(params): A callback function that returns an object of CSS styles to apply to the row.getRowClass(params): A callback function that returns a string or array of strings of CSS class names to apply to the row.
Example using getRowStyle to highlight rows:
import React, { useState, useMemo } 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 MyGridComponent = () => {
const [rowData] = useState([
{ make: 'Toyota', model: 'Celica', price: 35000, type: 'Sedan' },
{ make: 'Ford', model: 'Mondeo', price: 32000, type: 'Sedan' },
{ make: 'Porsche', model: 'Boxster', price: 72000, type: 'Sports' },
{ make: 'BMW', model: 'M3', price: 60000, type: 'Sports' },
{ make: 'Honda', model: 'Civic', price: 25000, type: 'Hatchback' }
]);
const [columnDefs] = useState([
{ field: 'make' },
{ field: 'model' },
{ field: 'price' },
{ field: 'type' }
]);
const defaultColDef = useMemo(() => ({
flex: 1,
minWidth: 100,
resizable: true,
sortable: true,
filter: true,
}), []);
const getRowStyle = useMemo(() => {
return params => {
if (params.data.type === 'Sports') {
return { background: '#ffe0b2' }; // Light orange background for sports cars
}
return null; // No custom style
};
}, []);
return (
<div className="ag-theme-alpine" style={{ height: 400, width: 600 }}>
<AgGridReact
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
animateRows={true}
getRowStyle={getRowStyle} // Apply row style here
/>
</div>
);
};
export default MyGridComponent;
Header Styling
You can style column headers globally or individually:
headerClass: IncolumnDefs, applies classes to individual column headers.headerComponent: Provides full control by allowing you to render a custom React component for the header.- CSS variables: As seen before, variables like
--ag-header-background-colorcan change header appearance globally for a theme.
Example using headerClass:
const [columnDefs] = useState([
{ field: 'make', headerClass: 'my-custom-header' },
{ field: 'model' },
{ field: 'price', headerClass: ['price-header', 'bold-header'] }
]);
/* MyGridComponent.css */
.my-custom-header {
background-color: #6c757d !important; /* Important to override theme */
color: white !important;
}
.bold-header {
font-weight: bold;
}
Note: Using !important might be necessary for direct CSS overrides to ensure your styles take precedence over the theme's rules.
Accessibility Considerations
When customizing AG-Grid's appearance, always keep accessibility in mind:
- Color Contrast: Ensure sufficient contrast between text and background colors for readability (WCAG guidelines often recommend 4.5:1 for normal text).
- Focus Indicators: Make sure focus states (e.g., when tabbing through cells) are clearly visible. AG-Grid's themes generally handle this, but custom styles could inadvertently hide them.
- Font Sizes: Use legible font sizes and allow for browser-level text resizing.
Best Practices for Theming and Styling
- Start Simple: Begin with a built-in theme and use CSS variables for minor tweaks.
- Organize Styles: Keep your AG-Grid specific CSS/SCSS in dedicated files for maintainability.
- Leverage AG-Grid Features: Use
cellClassRules,rowClassRules, etc., before resorting to direct DOM manipulation or complex selectors. - Test Thoroughly: Always test your themed grid across different browsers and devices to ensure consistent appearance and functionality.
- Document Customizations: If you build a complex custom theme, document the variables and mixins you've used.
Conclusion
AG-Grid offers unparalleled flexibility when it comes to visual customization. Whether you need a quick change with a built-in theme and CSS variables or a complete brand-aligned redesign using SCSS, AG-Grid provides the tools. By mastering these theming and styling techniques, you can transform your data grids from purely functional components into fully integrated and aesthetically pleasing parts of your React application, significantly enhancing the user experience.