---
product: "AG Grid"
title: "Grid State"
description: "This section covers saving and restoring the grid state, such as the filter model, selected rows, etc."
framework: vue
version: "36.2.0"
related:
    - title: "Grid Context"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-data-grid/context/"
    - title: "Grid Lifecycle"
      url: "https://www.ag-grid.com/archive/36.2.0/vue-data-grid/grid-lifecycle/"
llms: "https://www.ag-grid.com/archive/36.2.0/llms.txt"
---

# Grid State

This section covers saving and restoring the grid state, such as the filter model, selected rows, etc.

## Saving and Restoring State

The following buttons log saving and restoring state to the developer console.

#### Grid State

```ts
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="reloadGrid()">Recreate Grid with Current 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 reloadGrid = () => {
      if (gridApi.value) {
        const state = gridApi.value.getState();
        gridVisible.value = false;
        setTimeout(() => {
          initialState.value = state;
          rowData.value = undefined;
          gridVisible.value = true;
        });
      }
    };
    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,
      reloadGrid,
      printState,
    };
  },
});

createApp(VueExample).mount("#app");
```

[Live example: Grid State](https://www.ag-grid.com/archive/36.2.0/examples/grid-state/grid-state/vue3/)

The initial state is provided via the grid option `initialState`. It is only read once when the grid is created.

```ts
<ag-grid-vue
    :initialState="initialState"
    /* other grid options ... */>
</ag-grid-vue>

this.initialState = {
    filter: {
        filterModel: {
            year: {
                filterType: 'set',
                values: ['2012'],
            }
        }
    },
    columnVisibility: {
        hiddenColIds: ['athlete'],
    },
    rowGroup: {
        groupColIds: ['athlete'],
    }
};
```

The current grid state can be retrieved by listening to the state updated event, which is fired with the latest state when it changes, or via `api.getState()`.

The state is also passed in the [Grid Pre-Destroyed Event](https://www.ag-grid.com/archive/36.2.0/vue-data-grid/grid-lifecycle/#grid-pre-destroyed), which can be used to get the state when the grid is destroyed.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `gridPreDestroyed` | `GridPreDestroyedEvent` |  |  |  |
| `stateUpdated` | `StateUpdatedEvent` |  |  |  |

## State Contents

The grid state is made up of the sections below, each of which can be provided or omitted independently. If applying some but not all of the column state properties, then `initialState.partialColumnState` must be set to `true`.

`partialColumnState` controls *which* column state sections you supply, not whether those sections may themselves be partial. Any section you include must match its documented shape.

The state also contains the grid version number. When applying state with older version numbers, any old state properties will be automatically migrated to the current format.

The grid state is designed to be serialisable, so any functions will be stripped out. For example, aggregation functions should be [Registered as Custom Functions](https://www.ag-grid.com/archive/36.2.0/vue-data-grid/aggregation-custom-functions/#registering-custom-functions) to work with state rather than being set as [Directly Applied Functions](https://www.ag-grid.com/archive/36.2.0/vue-data-grid/aggregation-custom-functions/#directly-applied-functions).

Properties available on the `GridState` interface.

| Property | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `version` | `string` |  |  |  |
| `aggregation` | `AggregationState` |  |  |  |
| `columnGroup` | `ColumnGroupState` |  |  |  |
| `columnOrder` | `ColumnOrderState` |  |  |  |
| `columnPinning` | `ColumnPinningState` |  |  |  |
| `columnSizing` | `ColumnSizingState` |  |  |  |
| `columnVisibility` | `ColumnVisibilityState` |  |  |  |
| `columnHeaderName` | `ColumnHeaderNameState` |  |  |  |
| `filter` | `FilterState` |  |  |  |
| `find` | `FindState` |  |  |  |
| `quickFilter` | `QuickFilterState` |  |  |  |
| `focusedCell` | `FocusedCellState` |  |  |  |
| `pagination` | `PaginationState` |  |  |  |
| `rowPinning` | `RowPinningState` |  |  |  |
| `pivot` | `PivotState` |  |  |  |
| `cellSelection` | `CellSelectionState` |  |  |  |
| `rowGroup` | `RowGroupState` |  |  |  |
| `rowGroupExpansion` | `RowGroupExpansionState` |  |  |  |
| `ssrmRowGroupExpansion` | `RowGroupExpansionState \| RowGroupBulkExpansionState` |  |  |  |
| `rowSelection` | `string[] \| ServerSideRowSelectionState \| ServerSideRowGroupSelectionState` |  |  |  |
| `scroll` | `ScrollState` |  |  |  |
| `sideBar` | `SideBarState` |  |  |  |
| `sort` | `SortState` |  |  |  |
| `showValuesAs` | `ShowValuesAsState` |  |  |  |
| `userColumns` | `UserColumnState[]` |  |  |  |
| `partialColumnState` | `boolean` |  |  |  |

> **Note**
>
> When restoring the current page using the [Server Side Row Model](https://www.ag-grid.com/archive/36.2.0/vue-data-grid/server-side-model/) or [Infinite Row Model](https://www.ag-grid.com/archive/36.2.0/vue-data-grid/infinite-scrolling/), additional configuration is required:
>
> - For the Server Side Row Model - set the `serverSideInitialRowCount` property to a value which includes the rows to be shown.
> - For the Infinite Row Model - set the `infiniteInitialRowCount` property to a value which includes the rows to be shown.

## Column and Group IDs

> **Warning**
>
> Give every column a `colId` or a `field`, and every column group a `groupId`. Without them, state can be restored onto the wrong column.

Columns are identified in the state by their [Column ID](https://www.ag-grid.com/archive/36.2.0/vue-data-grid/column-updating-definitions/#matching-columns), and [Column Groups](https://www.ag-grid.com/archive/36.2.0/vue-data-grid/column-groups/) by their `groupId`. These IDs are the only link between a saved state and the columns it describes, so they need to mean the same thing when the state is restored as they did when it was saved.

A column that provides neither `colId` nor `field` - one using only a `valueGetter`, for example - is given a positional ID instead. That ID follows the column's position in `columnDefs` rather than the column itself. If the definitions are reordered between saving and restoring, each column's state is applied to whichever column now occupies its old position.

This affects every column state section: sizes, sort, pinning, visibility, order and header names. A restored grid can silently show another column's width, or a header the user renamed on the wrong column.

Column groups behave the same way. A group definition without a `groupId` is given a generated ID which changes when the column definitions change, so the open / closed state of that group may not be restored.

## Setting State

The best way to restore grid state is via initial state as described above. However, it is also possible to restore state on an existing grid via `api.setState(state)`.

> **Note**
>
> `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.

It is possible to maintain the existing state for individual state contents by passing a second argument to `setState` that contains the top-level properties to ignore. E.g. `api.setState(state, ['filter'])` will maintain the existing filter state in the grid.

Anything the provided state omits is reset rather than left as is. For example, a state without a `quickFilter` section clears the quick filter value in the toolbar.

#### Setting State

```ts
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="saveState()">Save State</button>
                        <button v-on:click="reloadGrid()">Recreate Grid with No 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="setState"
                    :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"
                    :rowData="rowData"
                    @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 },
        ],
      },
      {
        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 savedState = ref<GridState>();

    const reloadGrid = () => {
      gridVisible.value = false;
      setTimeout(() => {
        rowData.value = undefined;
        gridVisible.value = true;
      });
    };
    const printState = () => {
      console.log("Grid state", gridApi.value!.getState());
    };
    const saveState = () => {
      const state = gridApi.value!.getState();
      savedState.value = state;
      console.log("Saved state", state);
    };
    const setState = () => {
      if (savedState.value) {
        gridApi.value!.setState(savedState.value);
        console.log("Set state", savedState.value);
      }
    };
    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,
      onGridReady,
      onGridPreDestroyed,
      onStateUpdated,
      reloadGrid,
      printState,
      saveState,
      setState,
    };
  },
});

createApp(VueExample).mount("#app");
```

[Live example: Setting State](https://www.ag-grid.com/archive/36.2.0/examples/grid-state/set-state/vue3/)

## Converting Column State to Grid State

State retrieved via the [Column State](https://www.ag-grid.com/archive/36.2.0/vue-data-grid/column-state/) APIs can be converted into grid state via the helper functions `convertColumnState` and `convertColumnGroupState`.

```
const state = {
    ...convertColumnState(columnState),
    ...convertColumnGroupState(columnGroupState)
};
```
