The Status Bar appears below the grid and contains Status Bar Panels. Panels can be Grid Provided Panels or Custom Status Bar Panels.
Configure the Status Bar with the statusBar grid property. The property takes a list of Status Bar Panels.
const statusBar = useMemo(() => {
return {
statusPanels: [
{ statusPanel: 'agTotalAndFilteredRowCountComponent' },
{ statusPanel: 'agTotalRowCountComponent' },
{ statusPanel: 'agFilteredRowCountComponent' },
{ statusPanel: 'agSelectedRowCountComponent' },
{ statusPanel: 'agAggregationComponent' }
]
};
}, []);
<AgGridReact statusBar={statusBar} />Some Status Panels only show when a Cell Selection is present.
"use client";
import React, {
useCallback,
useMemo,
useRef,
useState,
StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
CellSelectionOptions,
ClientSideRowModelModule,
ColDef,
ColGroupDef,
GridApi,
GridOptions,
ModuleRegistry,
NumberFilterModule,
RowSelectionModule,
RowSelectionOptions,
StatusBar,
TextFilterModule,
enableDevValidations,
} from "ag-grid-community";
import { CellSelectionModule, StatusBarModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";
if (process.env.NODE_ENV !== "production") {
enableDevValidations();
}
const modules = [
TextFilterModule,
RowSelectionModule,
ClientSideRowModelModule,
CellSelectionModule,
StatusBarModule,
NumberFilterModule,
];
const GridExample = () => {
const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
const [columnDefs, setColumnDefs] = useState<ColDef[]>([
{ field: "athlete", minWidth: 200 },
{ field: "age", filter: "agNumberColumnFilter" },
{ field: "country", minWidth: 200 },
{ field: "year" },
{ field: "date", minWidth: 180 },
{ field: "sport", minWidth: 200 },
{ field: "gold" },
{ field: "silver" },
{ field: "bronze" },
{ field: "total" },
]);
const defaultColDef = useMemo<ColDef>(() => {
return {
flex: 1,
minWidth: 100,
filter: true,
};
}, []);
const rowSelection = useMemo<
RowSelectionOptions | "single" | "multiple"
>(() => {
return { mode: "multiRow" };
}, []);
const statusBar = useMemo<StatusBar>(() => {
return {
statusPanels: [
{ statusPanel: "agTotalAndFilteredRowCountComponent" },
{ statusPanel: "agTotalRowCountComponent" },
{ statusPanel: "agFilteredRowCountComponent" },
{ statusPanel: "agSelectedRowCountComponent" },
{ statusPanel: "agAggregationComponent" },
],
};
}, []);
const { data, loading } = useFetchJson<IOlympicData>(
"https://www.ag-grid.com/example-assets/olympic-winners.json",
);
return (
<AgGridProvider modules={modules}>
<div style={containerStyle}>
<div style={gridStyle}>
<AgGridReact<IOlympicData>
rowData={data}
loading={loading}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
rowSelection={rowSelection}
cellSelection={true}
statusBar={statusBar}
/>
</div>
</div>
</AgGridProvider>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(
<StrictMode>
<GridExample />
</StrictMode>,
);
export interface IOlympicData {
athlete: string,
age: number,
country: string,
year: number,
date: string,
sport: string,
gold: number,
silver: number,
bronze: number,
total: number
} import { useState, useEffect } from 'react';
/**
* Fetch example Json data
* Not recommended for production use!
*/
export const useFetchJson = <T,>(url:string, limit?: number) => {
const [data, setData] = useState<T[]>();
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
// Note error handling is omitted here for brevity
const response = await fetch(url);
const json = await response.json();
const data = limit ? json.slice(0, limit) : json;
setData(data);
setLoading(false);
};
fetchData();
}, [url, limit]);
return { data, loading };
}; Provided Panels Copy Link
The Status Bar Panels provided by the grid are as follows:
agTotalRowCountComponent: Provides the total row count.agTotalAndFilteredRowCountComponent: Provides the total and filtered row count.agFilteredRowCountComponent: Provides the filtered row count.agSelectedRowCountComponent: Provides the selected row count.agAggregationComponent: Provides aggregations on the selected range.
Configuration Copy Link
The align property can be left, center or right (default).
The key is used for Accessing Panel Instances via the grid API getStatusPanel(key). This can be useful for interacting with Custom Panels.
Additional props are passed to Status Panels using statusPanelParams. The provided panel agAggregationComponent can have aggFuncs passed.
const statusBar = useMemo(() => {
return {
statusPanels: [
{
key: 'aUniqueString',
statusPanel: 'agTotalRowCountComponent',
align: 'left'
},
{
statusPanel: 'agAggregationComponent',
statusPanelParams: {
// possible values are: 'count', 'sum', 'min', 'max', 'avg'
aggFuncs: ['avg', 'sum']
}
}
]
};
}, []);
<AgGridReact statusBar={statusBar} />Labels (e.g. "Rows", "Total Rows", "Average") and number formatting are changed using the grid's Localisation.
The Aggregation Panel agAggregationComponent works with number and bigint values. When bigint values are present, avg uses integer division and discards the fractional part.
"use client";
import React, {
useCallback,
useMemo,
useRef,
useState,
StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
CellSelectionOptions,
ClientSideRowModelModule,
ColDef,
ColGroupDef,
GridApi,
GridOptions,
ModuleRegistry,
StatusBar,
enableDevValidations,
} from "ag-grid-community";
import { CellSelectionModule, StatusBarModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";
if (process.env.NODE_ENV !== "production") {
enableDevValidations();
}
const modules = [
ClientSideRowModelModule,
CellSelectionModule,
StatusBarModule,
];
const GridExample = () => {
const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
const [columnDefs, setColumnDefs] = useState<ColDef[]>([
{ field: "athlete", minWidth: 200 },
{ field: "age" },
{ field: "country", minWidth: 200 },
{ field: "year" },
{ field: "date", minWidth: 180 },
{ field: "sport", minWidth: 200 },
{ field: "gold" },
{ field: "silver" },
{ field: "bronze" },
{ field: "total" },
]);
const defaultColDef = useMemo<ColDef>(() => {
return {
flex: 1,
minWidth: 100,
};
}, []);
const statusBar = useMemo<StatusBar>(() => {
return {
statusPanels: [
{
statusPanel: "agTotalRowCountComponent",
align: "left",
},
{
statusPanel: "agAggregationComponent",
statusPanelParams: {
aggFuncs: ["avg", "sum"],
},
},
],
};
}, []);
const { data, loading } = useFetchJson<IOlympicData>(
"https://www.ag-grid.com/example-assets/olympic-winners.json",
);
return (
<AgGridProvider modules={modules}>
<div style={containerStyle}>
<div style={gridStyle}>
<AgGridReact<IOlympicData>
rowData={data}
loading={loading}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
statusBar={statusBar}
cellSelection={true}
/>
</div>
</div>
</AgGridProvider>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(
<StrictMode>
<GridExample />
</StrictMode>,
);
export interface IOlympicData {
athlete: string,
age: number,
country: string,
year: number,
date: string,
sport: string,
gold: number,
silver: number,
bronze: number,
total: number
} import { useState, useEffect } from 'react';
/**
* Fetch example Json data
* Not recommended for production use!
*/
export const useFetchJson = <T,>(url:string, limit?: number) => {
const [data, setData] = useState<T[]>();
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
// Note error handling is omitted here for brevity
const response = await fetch(url);
const json = await response.json();
const data = limit ? json.slice(0, limit) : json;
setData(data);
setLoading(false);
};
fetchData();
}, [url, limit]);
return { data, loading };
}; The Status Bar sizes its height to fit content. When no panels are visible, the Status Bar will have zero height (not be shown). Add CSS to have a fixed height on the Status Bar.
.ag-status-bar {
min-height: 35px;
} Value Formatting Copy Link
Each Status Bar Panel can have its displayed values customised using a valueFormatter function. This allows for formatting values before they are rendered in the UI.
The valueFormatter function is provided in the statusPanelParams object.
const statusBar = useMemo(() => {
return {
statusPanels: [
{
statusPanel: 'agTotalAndFilteredRowCountComponent',
statusPanelParams: {
valueFormatter: (statusPanelValueFormatterParams) => {
const { value } = statusPanelValueFormatterParams;
if (value > 1000) {
return value / 1000 + ' K';
}
return String(value);
}
}
},
]
};
}, []);
<AgGridReact statusBar={statusBar} /> IProvidedStatusPanelParams Copy Link
Properties available on the IProvidedStatusPanelParams interface.
(params: IStatusPanelValueFormatterParams) => string |
"use client";
import React, {
useCallback,
useMemo,
useRef,
useState,
StrictMode,
} from "react";
import { createRoot } from "react-dom/client";
import { AgGridReact, AgGridProvider } from "ag-grid-react";
import {
CellSelectionOptions,
ClientSideRowModelModule,
ColDef,
ColGroupDef,
GridApi,
GridOptions,
IStatusPanelValueFormatterParams,
ModuleRegistry,
StatusBar,
enableDevValidations,
} from "ag-grid-community";
import { CellSelectionModule, StatusBarModule } from "ag-grid-enterprise";
import { IOlympicData } from "./interfaces";
import { useFetchJson } from "./useFetchJson";
if (process.env.NODE_ENV !== "production") {
enableDevValidations();
}
const modules = [
ClientSideRowModelModule,
CellSelectionModule,
StatusBarModule,
];
const GridExample = () => {
const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
const [columnDefs, setColumnDefs] = useState<ColDef[]>([
{ field: "athlete", minWidth: 200 },
{ field: "age" },
{ field: "country", minWidth: 200 },
{ field: "year" },
{ field: "date", minWidth: 180 },
{ field: "sport", minWidth: 200 },
{ field: "gold" },
{ field: "silver" },
{ field: "bronze" },
{ field: "total" },
]);
const defaultColDef = useMemo<ColDef>(() => {
return {
flex: 1,
minWidth: 100,
};
}, []);
const statusBar = useMemo<StatusBar>(() => {
return {
statusPanels: [
{
statusPanel: "agTotalRowCountComponent",
align: "left",
statusPanelParams: {
valueFormatter: (params: IStatusPanelValueFormatterParams) => {
const { value, bigintValue } = params;
if (bigintValue != null) {
return bigintValue.toString();
}
if (typeof value === "number" && value > 1000) {
return (value / 1000).toFixed(1) + " K";
}
return String(value);
},
},
},
],
};
}, []);
const { data, loading } = useFetchJson<IOlympicData>(
"https://www.ag-grid.com/example-assets/olympic-winners.json",
);
return (
<AgGridProvider modules={modules}>
<div style={containerStyle}>
<div style={gridStyle}>
<AgGridReact<IOlympicData>
rowData={data}
loading={loading}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
statusBar={statusBar}
cellSelection={true}
/>
</div>
</div>
</AgGridProvider>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(
<StrictMode>
<GridExample />
</StrictMode>,
);
export interface IOlympicData {
athlete: string,
age: number,
country: string,
year: number,
date: string,
sport: string,
gold: number,
silver: number,
bronze: number,
total: number
} import { useState, useEffect } from 'react';
/**
* Fetch example Json data
* Not recommended for production use!
*/
export const useFetchJson = <T,>(url:string, limit?: number) => {
const [data, setData] = useState<T[]>();
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async () => {
setLoading(true);
// Note error handling is omitted here for brevity
const response = await fetch(url);
const json = await response.json();
const data = limit ? json.slice(0, limit) : json;
setData(data);
setLoading(false);
};
fetchData();
}, [url, limit]);
return { data, loading };
}; Custom Panels Copy Link
Applications that are using Server-side Data or which require bespoke Status Bar Panels can provide their own custom Status Bar panels.
Clicking on the button in the status bar will log the number of selected rows to the developer console.
'use client';
import React, { StrictMode, useMemo, useState } from "react";
import { createRoot } from "react-dom/client";
import type {
ColDef,
RowSelectionOptions,
StatusPanelDef,
} from "ag-grid-community";
import {
ClientSideRowModelModule,
EventApiModule,
RowApiModule,
RowSelectionModule,
TextEditorModule,
TextFilterModule,
enableDevValidations,
} from "ag-grid-community";
import { CellSelectionModule, StatusBarModule } from "ag-grid-enterprise";
import { AgGridProvider, AgGridReact } from "ag-grid-react";
import ClickableStatusBarComponent from "./clickableStatusBarComponent";
import CountStatusBarComponent from "./countStatusBarComponent";
import "./styles.css";
// Enable extended validations only for development
if (process.env.NODE_ENV !== "production") {
enableDevValidations();
}
const modules = [
EventApiModule,
TextEditorModule,
TextFilterModule,
RowSelectionModule,
RowApiModule,
ClientSideRowModelModule,
StatusBarModule,
CellSelectionModule,
];
const rowSelection: RowSelectionOptions = {
mode: "multiRow",
};
const GridExample = () => {
const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
const gridStyle = useMemo(() => ({ height: "100%", width: "100%" }), []);
const [rowData, setRowData] = useState<any[]>([
{ row: "Row 1", name: "Michael Phelps" },
{ row: "Row 2", name: "Natalie Coughlin" },
{ row: "Row 3", name: "Aleksey Nemov" },
{ row: "Row 4", name: "Alicia Coutts" },
{ row: "Row 5", name: "Missy Franklin" },
{ row: "Row 6", name: "Ryan Lochte" },
{ row: "Row 7", name: "Allison Schmitt" },
{ row: "Row 8", name: "Natalie Coughlin" },
{ row: "Row 9", name: "Ian Thorpe" },
{ row: "Row 10", name: "Bob Mill" },
{ row: "Row 11", name: "Willy Walsh" },
{ row: "Row 12", name: "Sarah McCoy" },
{ row: "Row 13", name: "Jane Jack" },
{ row: "Row 14", name: "Tina Wills" },
]);
const [columnDefs, setColumnDefs] = useState<ColDef[]>([
{
field: "row",
},
{
field: "name",
},
]);
const defaultColDef = useMemo<ColDef>(() => {
return {
editable: true,
flex: 1,
minWidth: 100,
filter: true,
};
}, []);
const statusBar = useMemo<{
statusPanels: StatusPanelDef[];
}>(() => {
return {
statusPanels: [
{
statusPanel: CountStatusBarComponent,
},
{
statusPanel: ClickableStatusBarComponent,
},
{
statusPanel: "agAggregationComponent",
statusPanelParams: {
aggFuncs: ["count", "sum"],
},
},
],
};
}, []);
return (
<AgGridProvider modules={modules}>
<div style={containerStyle}>
<div style={gridStyle}>
<AgGridReact
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
rowSelection={rowSelection}
statusBar={statusBar}
/>
</div>
</div>
</AgGridProvider>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(
<StrictMode>
<GridExample />
</StrictMode>,
);
.container {
display: flex;
justify-content: center;
flex-direction: column;
margin: 5px;
background-color: lightgrey;
padding: 3px 5px 3px 5px;
border-radius: 5px;
}
.component {
margin-left: 5px;
padding-top: 0;
padding-bottom: 0;
}
.status-bar-input {
height: initial !important;
}
import React from "react";
import type { CustomStatusPanelProps } from "ag-grid-react";
export default (props: CustomStatusPanelProps) => {
const onClick = () => {
console.log("Selected Row Count: " + props.api.getSelectedRows().length);
};
return (
<div className="ag-status-name-value">
<span>
Status Bar Component
<input
type="button"
className="status-bar-input"
onClick={() => onClick()}
value="Click Me"
/>
</span>
</div>
);
};
import React, { useEffect, useState } from "react";
import type { CustomStatusPanelProps } from "ag-grid-react";
export default (props: CustomStatusPanelProps) => {
const [count, setCount] = useState(0);
useEffect(() => {
const onRowCountChanged = () => {
setCount(props.api.getDisplayedRowCount());
};
props.api.addEventListener("rowDataUpdated", onRowCountChanged);
// Get the initial count
onRowCountChanged();
return () => {
props.api.removeEventListener("rowDataUpdated", onRowCountChanged);
};
}, []);
return (
<div className="ag-status-name-value">
<span className="component">Row Count Component </span>
<span className="ag-status-name-value-value">{count}</span>
</div>
);
};
When a status bar component is instantiated then the following will be made available on props.
Properties available on the CustomStatusPanelProps<TData = any, TContext = any> interface.
string |
The grid api. |
Application context as set on gridOptions.context. |
Custom Panels are configured alongside Provided Panels.
<AgGridReact
statusBar: {{
statusPanels: [
{
statusPanel: MyStatusBarComponent
},
{
statusPanel: 'agAggregationComponent'
}
]
}}
...other props...
/>Custom Panels can listen to grid events to react to grid changes. An easy way to listen to grid events from inside a Status Panel is using the API provided via props.
const updateStatusBar = () => { ... }
useEffect(() => {
props.api.addEventListener('modelUpdated', updateStatusBar);
// Remove event listener when destroyed
return () => {
if (!props.api.isDestroyed()) {
props.api.removeEventListener('modelUpdated', updateStatusBar);
}
}
}, []); Accessing Instances Copy Link
Use the grid API getStatusPanel(key) to access a panel instance. This can be used to expose Custom Panels to the application.
Gets the status panel instance corresponding to the supplied id. |
Clicking on the button in the status bar will log the number of selected rows to the developer console.
'use client';
import React, {
StrictMode,
useCallback,
useMemo,
useRef,
useState,
} from "react";
import { createRoot } from "react-dom/client";
import type {
ColDef,
IStatusPanel,
RowSelectionOptions,
StatusPanelDef,
} from "ag-grid-community";
import {
ClientSideRowModelModule,
RowSelectionModule,
TextEditorModule,
TextFilterModule,
enableDevValidations,
} from "ag-grid-community";
import { CellSelectionModule, StatusBarModule } from "ag-grid-enterprise";
import { AgGridProvider, AgGridReact, getInstance } from "ag-grid-react";
import ClickableStatusBarComponent from "./clickableStatusBarComponent";
import "./styles.css";
// Enable extended validations only for development
if (process.env.NODE_ENV !== "production") {
enableDevValidations();
}
const modules = [
TextEditorModule,
TextFilterModule,
RowSelectionModule,
ClientSideRowModelModule,
StatusBarModule,
CellSelectionModule,
];
export interface IClickableStatusBar extends IStatusPanel {
setVisible(visible: boolean): void;
isVisible(): boolean;
}
const rowSelection: RowSelectionOptions = {
mode: "multiRow",
};
const GridExample = () => {
const gridRef = useRef<AgGridReact>(null);
const containerStyle = useMemo(() => ({ width: "100%", height: "100%" }), []);
const gridStyle = useMemo(() => ({ height: "90%", width: "100%" }), []);
const [rowData, setRowData] = useState<any[]>([
{ row: "Row 1", name: "Michael Phelps" },
{ row: "Row 2", name: "Natalie Coughlin" },
{ row: "Row 3", name: "Aleksey Nemov" },
{ row: "Row 4", name: "Alicia Coutts" },
{ row: "Row 5", name: "Missy Franklin" },
{ row: "Row 6", name: "Ryan Lochte" },
{ row: "Row 7", name: "Allison Schmitt" },
{ row: "Row 8", name: "Natalie Coughlin" },
{ row: "Row 9", name: "Ian Thorpe" },
{ row: "Row 10", name: "Bob Mill" },
{ row: "Row 11", name: "Willy Walsh" },
{ row: "Row 12", name: "Sarah McCoy" },
{ row: "Row 13", name: "Jane Jack" },
{ row: "Row 14", name: "Tina Wills" },
]);
const [columnDefs, setColumnDefs] = useState<ColDef[]>([
{
field: "row",
},
{
field: "name",
},
]);
const defaultColDef = useMemo<ColDef>(() => {
return {
editable: true,
flex: 1,
minWidth: 100,
filter: true,
};
}, []);
const statusBar = useMemo<{
statusPanels: StatusPanelDef[];
}>(() => {
return {
statusPanels: [
{
statusPanel: ClickableStatusBarComponent,
key: "statusBarCompKey",
},
{
statusPanel: "agAggregationComponent",
statusPanelParams: {
aggFuncs: ["count", "sum"],
},
},
],
};
}, []);
const toggleStatusBarComp = useCallback(() => {
getInstance(
gridRef.current!.api.getStatusPanel<IClickableStatusBar>(
"statusBarCompKey",
)!,
(statusBarComponent) => {
statusBarComponent!.setVisible(!statusBarComponent!.isVisible());
},
);
}, []);
return (
<AgGridProvider modules={modules}>
<div style={containerStyle}>
<button onClick={toggleStatusBarComp} style={{ marginBottom: "10px" }}>
Toggle Status Bar Component
</button>
<div style={gridStyle}>
<AgGridReact
ref={gridRef}
rowData={rowData}
columnDefs={columnDefs}
defaultColDef={defaultColDef}
rowSelection={rowSelection}
statusBar={statusBar}
/>
</div>
</div>
</AgGridProvider>
);
};
const root = createRoot(document.getElementById("root")!);
root.render(
<StrictMode>
<GridExample />
</StrictMode>,
);
.container {
display: flex;
justify-content: center;
flex-direction: column;
margin: 5px;
padding: 3px 5px 3px 5px;
border-radius: 5px;
}
.component {
margin-left: 5px;
padding-top: 0;
padding-bottom: 0;
}
import React, { forwardRef, useImperativeHandle, useState } from "react";
import type { CustomStatusPanelProps } from "ag-grid-react";
export default forwardRef((props: CustomStatusPanelProps, ref) => {
const [visible, setVisible] = useState(true);
const onClick = () => {
console.log("Selected Row Count: " + props.api.getSelectedRows().length);
};
useImperativeHandle(ref, () => {
return {
setVisible: (visible: boolean) => {
setVisible(visible);
},
isVisible: () => {
return visible;
},
};
});
if (visible) {
return (
<div className="container">
<div>
<span className="component">
Status Bar Component
<input type="button" onClick={() => onClick()} value="Click Me" />
</span>
</div>
</div>
);
}
return null;
});