Grid State is a serialisable object capturing a user's changes to the grid, such as sort, filters and column order. Save it to restore a view between sessions, or switch between saved configurations on demand.
Saving and Restoring State Copy Link
The following example shows how the current grid state can be saved and restored.
- Try sorting / re-sizing / hiding a column / apply a filter / scroll the grid / change the current page
- Click Recreate with State to destroy the grid and re-create using the saved state. Note how the grid returns to the same state.
- Alternatively click Save State, then Recreate without State to start from the column definitions, and Set State to restore the saved state.
import { createApp, defineComponent, ref, shallowRef } from "vue";
import type {
ColDef,
ColGroupDef,
GridApi,
GridPreDestroyedEvent,
GridReadyEvent,
GridState,
RowSelectionOptions,
StateUpdatedEvent,
Toolbar,
} from "ag-grid-community";
import { ModuleRegistry, enableDevValidations } from "ag-grid-community";
import { AllEnterpriseModule } from "ag-grid-enterprise";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
ModuleRegistry.registerModules([AllEnterpriseModule]);
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<div class="example-wrapper">
<div>
<span class="button-group">
<button v-on:click="recreateWithCurrentState()">Recreate with State</button>
<button v-on:click="saveState()">Save State</button>
<button v-on:click="recreateWithNoState()">Recreate without State</button>
<button v-on:click="setState()">Set State</button>
<button v-on:click="printState()">Print State</button>
</span>
</div>
<ag-grid-vue
v-if="gridVisible"
style="width: 100%; height: 100%;"
gridId="gridState"
:columnDefs="columnDefs"
@grid-ready="onGridReady"
:defaultColDef="defaultColDef"
:defaultColGroupDef="defaultColGroupDef"
:autoGroupColumnDef="autoGroupColumnDef"
:sideBar="true"
:toolbar="toolbar"
:pagination="true"
:rowSelection="rowSelection"
:cellSelection="true"
:calculatedColumns="true"
:enableRowPinning="true"
:suppressColumnMoveAnimation="true"
:ensureDomOrder="true"
:rowData="rowData"
:initialState="initialState"
@grid-pre-destroyed="onGridPreDestroyed"
@state-updated="onStateUpdated"
></ag-grid-vue>
</div>
</div>
`,
components: {
"ag-grid-vue": AgGridVue,
},
setup(props) {
const columnDefs = ref<(ColDef | ColGroupDef)[]>([
{ field: "athlete", minWidth: 150 },
{ field: "age" },
{ field: "country", minWidth: 150 },
{
headerName: "Competition",
groupId: "competition",
children: [
{ field: "year" },
{ field: "date", minWidth: 150 },
{ field: "sport", minWidth: 150 },
],
},
{
// Collapsible group with a stable groupId so open/closed columnGroup state can round-trip.
headerName: "Medals",
groupId: "medals",
children: [
{ field: "gold" },
{ field: "silver", columnGroupShow: "open" },
{ field: "bronze", columnGroupShow: "open" },
{ field: "total", columnGroupShow: "closed" },
],
},
]);
const gridApi = shallowRef<GridApi | null>(null);
const defaultColDef = ref<ColDef>({
flex: 1,
minWidth: 100,
filter: true,
enableRowGroup: true,
enablePivot: true,
enableValue: true,
headerNameEditable: true,
});
const defaultColGroupDef = ref<Partial<ColGroupDef>>({
headerNameEditable: true,
});
const autoGroupColumnDef = ref<ColDef>({ minWidth: 200 });
const rowSelection = ref<RowSelectionOptions>({
mode: "multiRow",
});
const toolbar = ref<Toolbar>({
items: ["agQuickFilterToolbarItem", "agFindToolbarItem"],
});
const rowData = ref<any[] | undefined>(undefined);
const gridVisible = ref(true);
const initialState = ref<GridState | undefined>(undefined);
const savedState = ref<GridState>();
const recreateGrid = (state?: GridState) => {
gridVisible.value = false;
setTimeout(() => {
initialState.value = state;
rowData.value = undefined;
gridVisible.value = true;
});
};
const recreateWithCurrentState = () =>
recreateGrid(gridApi.value!.getState());
const recreateWithNoState = () => recreateGrid();
const saveState = () => {
savedState.value = gridApi.value!.getState();
console.log("Saved state", savedState.value);
};
const setState = () => {
if (savedState.value) {
gridApi.value!.setState(savedState.value);
console.log("Set state", savedState.value);
}
};
const printState = () => {
console.log("Grid state", gridApi.value!.getState());
};
const onGridReady = (params: GridReadyEvent) => {
gridApi.value = params.api;
const updateData = (data: any[]) => (rowData.value = data);
fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
.then((resp) => resp.json())
.then((data) => updateData(data));
};
const onGridPreDestroyed = (params: GridPreDestroyedEvent) => {
console.log("Grid state on destroy (can be persisted)", params.state);
};
const onStateUpdated = (params: StateUpdatedEvent) => {
console.log("State updated", params.state);
};
return {
columnDefs,
gridApi,
defaultColDef,
defaultColGroupDef,
autoGroupColumnDef,
rowSelection,
toolbar,
rowData,
gridVisible,
initialState,
onGridReady,
onGridPreDestroyed,
onStateUpdated,
recreateWithCurrentState,
recreateWithNoState,
saveState,
setState,
printState,
};
},
});
createApp(VueExample).mount("#app");
Saving State Copy Link
The current grid state can be retrieved from the stateUpdated event, which fires whenever the state changes. The state is also available on the Grid Pre-Destroyed Event, which can be used to get the state when the grid is destroyed.
Invoked immediately before the grid is destroyed. This is useful for cleanup logic that needs to run before the grid is torn down. |
Grid state has been updated. |
The state can also be retrieved on demand via the gridApi.getState() method.
Get the current state of the grid.
Can be used in conjunction with the initialState grid option or api.setState() to save and restore grid state. |
It is the application's responsibility to persist the grid state to a suitable location.
Sparse State Object Copy Link
The state object only records what differs from the grid's defaults. Taking sort as an example, sortModel lists only the sorted columns, and if no column is sorted the sort property is omitted entirely.
// State of grid sorted by gold.
{
version: '36.3.0-beta.20261103.1437',
sort: { sortModel: [{ colId: 'gold', sort: 'desc' }] },
columnOrder: { orderedColIds: ['athlete', 'gold', 'silver', 'country'] },
}
// State after the user cleared the sort. The sort property is absent, not empty.
{
version: '36.3.0-beta.20261103.1437',
columnOrder: { orderedColIds: ['athlete', 'gold', 'silver', 'country'] },
}Because of this, an absent property means "none" rather than "unspecified". Restoring the second state must leave the grid unsorted. This matters when restoring a state that supplies only some of the column state properties, as covered in Column State and Column Definitions.
Restore via Initial State Copy Link
To restore a saved state to a new grid, pass the saved GridState to the grid option initialState. It is read once on creation, applying filters and groups before any data renders, so there is no flash of unfiltered or ungrouped data.
If cell data types are inferred and the row data is empty or not yet set, the filter state is applied once row data is added. To apply it straight away, set cellDataType: false on the default column definition, or provide a cell data type for every column.
<ag-grid-vue
:initialState="initialState"
/* other grid options ... */>
</ag-grid-vue>
// A state previously saved by the application
this.initialState = savedState;To exclude a property from being restored, for example the scroll position, remove it from the initialState object. The grid then uses its default for that property.
// Restore everything except the scroll position and the row selection.
const { scroll, rowSelection, ...stateToRestore } = savedState;
const gridOptions = {
initialState: stateToRestore,
};Column state properties are the exception. When initialState contains any of them, an omitted one is reset, overriding the matching value in the column definitions. See Column State and Column Definitions.
Restore via API Copy Link
To restore state on an existing grid use the api.setState(state) method. This enables, for example, a user to save multiple configurations of the same grid and switch between them on demand.
// Restore a saved state onto an existing grid
api.setState(savedState);Set the current state of the grid.
Can be used in conjunction with api.getState() or onStateUpdated to save and restore grid state.
The provided state replaces the grid state rather than patching it: every section it omits is reset unless listed in propertiesToIgnore.
propertiesToIgnore: Top-level state sections to leave as they are, e.g. ['filter'] keeps the current filters. |
setState should only be used to restore grid state. The grid does not support being used as a controlled component, so do not call this on every state update.
To exclude properties from being restored, pass their names as the second argument, propertiesToIgnore. Those properties are left as they are on the grid.
// Restore a saved state but keep the current filter state of the grid.
api.setState(savedState, ['filter']);Every property the provided state omits is reset because of the sparse nature of the state object. So a hand-built state containing only columnOrder will clear the sort, filters, row groups, pinning and every other property.
The example below switches between full states captured with api.getState().
- Default View applies the state captured when the grid first rendered, before any view was applied.
- Medals by Country and Swimming Leaders apply states saved after a user configured the grid.
- Column Order Only applies a hand-built state containing just
columnOrder, showing that omitted properties are reset. - Toggle Ignore Filter to conditionally pass
['filter']aspropertiesToIgnoreto enable maintaining the current filter state while switching views.
import {
createApp,
defineComponent,
onBeforeMount,
ref,
shallowRef,
} from "vue";
import { AgGridVue } from "ag-grid-vue3";
import {
AutoGroupColumnDef,
ColDef,
ColGroupDef,
FirstDataRenderedEvent,
GridApi,
GridOptions,
GridReadyEvent,
GridState,
GridStateKey,
ModuleRegistry,
SideBarDef,
enableDevValidations,
} from "ag-grid-community";
import { AllEnterpriseModule } from "ag-grid-enterprise";
import "./styles.css";
import { savedStates } from "./savedStates";
import { IOlympicData } from "./interfaces";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
ModuleRegistry.registerModules([AllEnterpriseModule]);
let defaultState: GridState | undefined;
// `propertiesToIgnore` lists the properties to leave untouched when the state is applied.
function getPropertiesToIgnore(): GridStateKey[] | undefined {
const ignoreFilter =
document.querySelector<HTMLInputElement>("#ignoreFilter")!.checked;
return ignoreFilter ? ["filter"] : undefined;
}
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<div class="example-wrapper">
<div>
<span class="button-group">
<button v-on:click="applyDefaultView()">Default View</button>
<button v-on:click="applyView('medalsByCountry')">Medals by Country</button>
<button v-on:click="applyView('swimmingLeaders')">Swimming Leaders</button>
<button v-on:click="setColumnOrderOnly()">Column Order Only</button>
<button v-on:click="filterCountry()">Filter: United States</button>
<label>
<input id="ignoreFilter" type="checkbox">
Ignore Filter
</label>
</span>
</div>
<ag-grid-vue
style="width: 100%; height: 100%;"
@grid-ready="onGridReady"
:gridId="gridId"
:columnDefs="columnDefs"
:defaultColDef="defaultColDef"
:autoGroupColumnDef="autoGroupColumnDef"
:rowGroupPanelShow="rowGroupPanelShow"
:sideBar="sideBar"
:rowData="rowData"
@first-data-rendered="onFirstDataRendered"></ag-grid-vue>
</div>
</div>
`,
components: {
"ag-grid-vue": AgGridVue,
},
setup(props) {
const gridApi = shallowRef<GridApi<IOlympicData> | null>(null);
const gridId = ref("savedViews");
const columnDefs = ref<ColDef[]>([
{ field: "athlete", minWidth: 150 },
{ field: "country", minWidth: 150 },
{ field: "sport", minWidth: 150 },
{ field: "year" },
{ field: "gold" },
{ field: "silver" },
{ field: "bronze" },
{ field: "total" },
]);
const defaultColDef = ref<ColDef>({
flex: 1,
minWidth: 100,
filter: true,
floatingFilter: true,
enableRowGroup: true,
enableValue: true,
});
const autoGroupColumnDef = ref<AutoGroupColumnDef>({
minWidth: 200,
});
const rowGroupPanelShow = ref<"always" | "onlyWhenGrouping" | "never">(
"always",
);
const sideBar = ref<SideBarDef | string | string[] | boolean | null>(
"columns",
);
const rowData = ref<IOlympicData[]>(null);
function onFirstDataRendered(event: FirstDataRenderedEvent<IOlympicData>) {
// Capture the state before any view is applied, so the default view can be restored.
defaultState = event.api.getState();
}
function applyDefaultView() {
if (defaultState) {
gridApi.value.setState(defaultState, getPropertiesToIgnore());
}
}
function filterCountry() {
gridApi.value.setFilterModel({
country: { filterType: "set", values: ["United States"] },
});
}
function applyView(viewName: string) {
const state = savedStates[viewName];
gridApi.value.setState(state, getPropertiesToIgnore());
console.log(`Applied view "${viewName}"`, state);
}
function setColumnOrderOnly() {
// A sparse state: every property it omits is reset unless it is ignored.
gridApi.value.setState(
{
columnOrder: {
orderedColIds: [
"total",
"gold",
"silver",
"bronze",
"athlete",
"country",
"sport",
"year",
],
},
},
getPropertiesToIgnore(),
);
}
const onGridReady = (params: GridReadyEvent) => {
gridApi.value = params.api;
const updateData = (data) => (rowData.value = data);
fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
.then((resp) => resp.json())
.then((data) => updateData(data));
};
return {
gridApi,
gridId,
columnDefs,
defaultColDef,
autoGroupColumnDef,
rowGroupPanelShow,
sideBar,
rowData,
onGridReady,
onFirstDataRendered,
applyDefaultView,
filterCountry,
applyView,
setColumnOrderOnly,
};
},
});
const app = createApp(VueExample);
app.mount("#app");
Column State and Column Definitions Copy Link
Column state properties such as sort, hide, pinned and aggFunc have two possible sources: the grid state and the column definitions. When initialState includes some but not all of the column state properties, the grid must decide what to do with the missing ones.
By default the missing properties are reset, overriding the column definition values. This follows from the sparse nature of the state object: a saved state with no sort property came from an unsorted grid, and restoring it must produce an unsorted grid even if a column definition sets a sort.
In the snippet below only columnOrder is provided, so the sort: 'asc' on Country is overridden and the grid is created unsorted.
columnDefs: [
{ field: 'athlete' },
{ field: 'country', sort: 'asc' },
],
initialState: {
// Only the column order is provided, so every other column state property is reset.
columnOrder: {
orderedColIds: ['country', 'athlete'],
},
}To fall back to the column definition values instead, set partialColumnState: true. Missing column state properties then keep whatever the column definitions specify. This is the right choice for a state built by hand. For a state saved from the grid, a missing property means the user had none, and the flag would wrongly reapply the column definition values.
In the example below the column definitions pin Country, hide Year and sum Gold and Silver into a grand total row. Each button recreates the grid with a different initialState.
- No State shows the grid as defined by the column definitions.
- Column Order (overrides defaults) supplies only
columnOrder. Country is unpinned, Year appears and the totals are blank. - Column Order + partialColumnState (keeps defaults) supplies the same
columnOrderwithpartialColumnState: true. The order is applied and the column definition defaults remain.
import { createApp, defineComponent, ref, shallowRef } from "vue";
import type {
ColDef,
GridApi,
GridReadyEvent,
GridState,
} from "ag-grid-community";
import { ModuleRegistry, enableDevValidations } from "ag-grid-community";
import { AllEnterpriseModule } from "ag-grid-enterprise";
import { AgGridVue } from "ag-grid-vue3";
import "./styles.css";
if (process.env.NODE_ENV !== "production") {
// Enable extended validations only for development
enableDevValidations();
}
ModuleRegistry.registerModules([AllEnterpriseModule]);
// Only the column order is supplied; every other column state section is omitted.
const columnOrderState: GridState = {
columnOrder: {
orderedColIds: ["gold", "silver", "athlete", "sport", "country", "year"],
},
};
const VueExample = defineComponent({
template: `
<div style="height: 100%">
<div class="example-wrapper">
<div>
<span class="button-group">
<button v-on:click="recreateWithNoState()">No State</button>
<button v-on:click="recreateWithColumnOrder()">Column Order (overrides defaults)</button>
<button v-on:click="recreateWithPartialColumnOrder()">
Column Order + partialColumnState (keeps defaults)
</button>
</span>
</div>
<ag-grid-vue
v-if="gridVisible"
style="width: 100%; height: 100%;"
gridId="partialColumnState"
:columnDefs="columnDefs"
:defaultColDef="defaultColDef"
grandTotalRow="bottom"
:rowData="rowData"
:initialState="initialState"
@grid-ready="onGridReady"
></ag-grid-vue>
</div>
</div>
`,
components: {
"ag-grid-vue": AgGridVue,
},
setup(props) {
const columnDefs = ref<ColDef[]>([
{ field: "athlete" },
{ field: "country", pinned: "left" },
{ field: "year", hide: true },
{ field: "sport" },
{ field: "gold", aggFunc: "sum" },
{ field: "silver", aggFunc: "sum" },
]);
const gridApi = shallowRef<GridApi | null>(null);
const defaultColDef = ref<ColDef>({
flex: 1,
minWidth: 100,
});
const rowData = ref<any[] | undefined>(undefined);
const gridVisible = ref(true);
const initialState = ref<GridState | undefined>(undefined);
const recreateGrid = (state?: GridState) => {
gridVisible.value = false;
console.log("Recreating grid with initialState", state);
setTimeout(() => {
initialState.value = state;
rowData.value = undefined;
gridVisible.value = true;
});
};
const recreateWithNoState = () => recreateGrid();
const recreateWithColumnOrder = () => recreateGrid(columnOrderState);
const recreateWithPartialColumnOrder = () =>
recreateGrid({ ...columnOrderState, partialColumnState: true });
const onGridReady = (params: GridReadyEvent) => {
gridApi.value = params.api;
const updateData = (data: any[]) => (rowData.value = data);
fetch("https://www.ag-grid.com/example-assets/olympic-winners.json")
.then((resp) => resp.json())
.then((data) => updateData(data));
};
return {
columnDefs,
gridApi,
defaultColDef,
rowData,
gridVisible,
initialState,
onGridReady,
recreateWithNoState,
recreateWithColumnOrder,
recreateWithPartialColumnOrder,
};
},
});
createApp(VueExample).mount("#app");
Compatibility Copy Link
Column and Group Ids Copy Link
Columns are identified in the state by their Column ID, and Column Groups by their groupId. A column that provides neither colId nor field is given a positional ID. If the column definitions are reordered between saving and restoring, column state could be restored to the wrong column.
For best results ensure columns and groups have unique field or explicit colId and groups have an explicit groupId.
Grid State API vs Column State API Copy Link
Grid state and Column State overlap: the column state properties of grid state carry the same information as Column State, in a different shape. Which one to use depends on the task:
- Grid state saves and restores the grid as a whole, columns included. It is typically round-tripped through storage between sessions, and restoring it updates all columns together.
- Column State targets one aspect of the columns directly, in place, without touching anything else. Use
api.applyColumnState()for a one-off change such as reordering or resizing a subset of columns while leaving sort, filters and the rest of the grid untouched. See Applying Partial State for more examples.
If code was already using Column State alongside other custom APIs to manage grid-level state by hand, convertColumnState and convertColumnGroupState convert that Column State into the equivalent grid state sections:
import { convertColumnState, convertColumnGroupState } from 'ag-grid-community';
const state = {
...convertColumnState(columnState),
...convertColumnGroupState(columnGroupState),
}; Versioned State Copy Link
The grid state includes the version it was generated from. This enables grid states generated on older versions of the grid to be consumed by newer versions of the grid. If there is a change in format the grid will automatically apply the conversion to the old state.
Serializable State Copy Link
The grid state is designed to be serialisable, so any functions will be stripped out. This has implications for features such as Aggregation. If a custom aggregation function has been provided it must be Registered as Custom Functions via a string, as opposed to directly registering the function with the column. This enables the grid state to safely store the aggFunc string value against the column. A column using an inline aggregation function is left out of the aggregation property, so a state saved from such a grid does not restore that aggregation.
API Reference Copy Link
GridState Copy Link
Properties available on the GridState interface.
Grid version number |
Opened Column Groups, and column group header names edited by end users |
Column Filters and Advanced Filter |
Find search value and active match. Works for Client-Side Row Model only, and only when the Quick Access Toolbar is configured with agFindToolbarItem; otherwise the findSearchValue grid option is the only source
|
Quick Filter search text. Only captured and restored when the Quick Access Toolbar is configured with agQuickFilterToolbarItem; otherwise the quickFilterText grid option is the only source
|
Currently focused cell. Works for Client-Side Row Model only |
Current page and page size. With the Server Side Row Model or Infinite Row Model, restoring a page beyond the rows the grid already knows about needs serverSideInitialRowCount or infiniteInitialRowCount respectively set high enough to cover it, otherwise the grid restores the last page it knows about instead.
|
Currently manually pinned rows |
Currently selected cell ranges |
Currently expanded group rows |
Currently expanded Server-Side Row Model group rows when using ssrmExpandAllAffectsAllRows |
Currently selected rows. For Server-Side Row Model, will be ServerSideRowSelectionState | ServerSideRowGroupSelectionState, for other row models, will be an array of row IDs. Can only be set for Client-Side Row Model and Server-Side Row Model.
|
Current scroll position. Works for Client-Side Row Model only |
Current Side Bar positioning and opened tool panel, including the state of each tool panel |
Columns the user created or removed at runtime, such as Calculated Columns, along with the column definition properties they changed. Unlike the other sections, which configure existing columns, this section can create and remove them.
|
GridState (column properties) Copy Link
The following properties hold column state and are affected by partialColumnState.
Aggregation Functions (column state) |
Column Order (column state) |
Left/right Pinned Columns (column state) |
Column Sizes - width/flex (column state) |
Hidden Columns (column state) |
Column Header Names edited by end users (column state) |
Current pivot mode and pivot columns, and pivot column label sort (column state) |
Current Row Group Columns (column state) |
Current sort columns and direction, ordered by sortIndex (column state) |
The per-column "Show Values As" mode (column state) |
Set to true when initialState supplies some but not all of the column state sections. Without it, the omitted sections are reset, overriding column definition values such as hide, pinned or aggFunc.api.setState; use the second argument propertiesToIgnore to leave sections untouched. |