---
title: "Widget Configuration"
framework: vue
version: "2.1.2"
---

# Widget Configuration

Widgets can be customised in multiple ways, including changing the list of available widgets, as well as changing the configuration for individual widgets.

## Customise the Available Widgets

#### Customise the Available Widgets

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgStudio } from "ag-studio-vue3";
import {
  AgDataEngine,
  AgDataSourcesDefinition,
  AgDefaultRegistry,
  AgReportState,
  AgStudioApi,
  AgStudioApiReadyEvent,
  AgStudioMode,
  AgStudioProperties,
  AgWidgetsConfig,
  createWidgets,
} from "ag-studio";

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div style="display: flex; flex-direction: column; height: 100%">
      <ag-studio
        style="width: 100%; height: 100%;"
        class="my-studio-container"
        @api-ready="onApiReady"
        :initialState="initialState"
        :mode="mode"
        :widgets="widgets"
        :data="data"></ag-studio>
      </div>
        </div>
    `,
  components: {
    "ag-studio": AgStudio,
  },
  setup(props) {
    const studioApi = shallowRef<AgStudioApi | null>(null);
    const initialState = ref<AgReportState>({
      pages: [
        {
          id: "a",
          widgets: {
            "1": {
              type: "grid",
              dataMapping: {
                cols: [
                  { id: "medals.country" },
                  { id: "medals.sport" },
                  { id: "medals.gold", aggregation: "sum" },
                  { id: "medals.silver", aggregation: "sum" },
                  { id: "medals.bronze", aggregation: "sum" },
                  { id: "medals.total", aggregation: "sum" },
                ],
              },
            },
          },
          widgetLayout: {
            "1": {
              xTrack: 0,
              yTrack: 0,
              xSpan: 24,
              ySpan: 16,
            },
          },
        },
      ],
      selectedPageId: "a",
      panels: {
        filters: {
          collapsed: true,
        },
        data: {
          collapsed: true,
        },
      },
    });
    const mode = ref<AgStudioMode>("edit");
    const widgets = ref<
      | AgWidgetsConfig
      | ((widgets: AgWidgetsConfig<AgDefaultRegistry>) => AgWidgetsConfig)
    >((config: AgWidgetsConfig) =>
      createWidgets({
        menu: [
          {
            label: "Popular",
            widgetIds: ["grid", "value"],
          },
          {
            label: "Other",
            widgetIds: ["text", "button-filter"],
            collapsed: true,
          },
          config.menu[0],
        ],
        defaultType: "value",
      }),
    );
    const data = ref<AgDataSourcesDefinition | AgDataEngine>(null);

    const onApiReady = (params: AgStudioApiReadyEvent) => {
      studioApi.value = params.api;

      const getData = (data) => ({ sources: [{ id: "medals", data }] });

      fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
        .then((resp) => resp.json())
        .then((respData) => (data.value = getData(respData)));
    };

    return {
      studioApi,
      initialState,
      mode,
      widgets,
      data,
      onApiReady,
    };
  },
});

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

[Live example: Customise the Available Widgets](https://www.ag-grid.com/studio/examples/widget-configuration/customise-available-widgets/vue3/)

The example above changes the list of available widgets to:

- Add new groups of widgets
- Show one of the groups collapsed by default
- Re-use one of the default widget groups
- Change the default widget type when dragging fields to the Value widget

```ts
<ag-studio
    :widgets="widgets"
    /* other studio properties ... */>
</ag-studio>

this.widgets = createWidgets({
    menu: [
        // new menu configuration
    ],
    defaultType: 'value',
});
```

See the [Widget Configuration API](#widget-configuration-api) below for details on the `createWidgets` helper function.

## Change the Configuration for Individual Widgets

#### Change the Configuration for Individual Widgets

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgStudio } from "ag-studio-vue3";
import {
  AgBaseWidgetDefinition,
  AgDataEngine,
  AgDataSourcesDefinition,
  AgDefaultRegistry,
  AgFormTabGroup,
  AgGridWidget,
  AgPath,
  AgReportState,
  AgStudioApi,
  AgStudioApiReadyEvent,
  AgStudioMode,
  AgStudioProperties,
  AgWidgetsConfig,
  createWidgets,
} from "ag-studio";

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div style="display: flex; flex-direction: column; height: 100%">
      <ag-studio
        style="width: 100%; height: 100%;"
        class="my-studio-container"
        @api-ready="onApiReady"
        :initialState="initialState"
        :mode="mode"
        :widgets="widgets"
        :data="data"></ag-studio>
      </div>
        </div>
    `,
  components: {
    "ag-studio": AgStudio,
  },
  setup(props) {
    const studioApi = shallowRef<AgStudioApi | null>(null);
    const initialState = ref<AgReportState>({
      pages: [
        {
          id: "a",
          widgets: {
            "1": {
              type: "grid",
              dataMapping: {
                cols: [
                  { id: "medals.country" },
                  { id: "medals.sport" },
                  { id: "medals.gold", aggregation: "sum" },
                  { id: "medals.silver", aggregation: "sum" },
                  { id: "medals.bronze", aggregation: "sum" },
                  { id: "medals.total", aggregation: "sum" },
                ],
              },
            },
            "2": {
              type: "column-chart-grouped",
              dataMapping: {
                categoryKey: [{ id: "medals.country" }],
                valueKey: [
                  { id: "medals.gold", aggregation: "sum" },
                  { id: "medals.silver", aggregation: "sum" },
                  { id: "medals.bronze", aggregation: "sum" },
                ],
                tooltipKey: [],
              },
            },
          },
          widgetLayout: {
            "1": {
              xTrack: 0,
              yTrack: 0,
              xSpan: 24,
              ySpan: 16,
            },
            "2": {
              xTrack: 0,
              yTrack: 16,
              xSpan: 24,
              ySpan: 16,
            },
          },
          selection: {
            type: "widget",
            id: "1",
          },
        },
      ],
      selectedPageId: "a",
      panels: {
        filters: {
          collapsed: true,
        },
        data: {
          collapsed: true,
        },
      },
    });
    const mode = ref<AgStudioMode>("edit");
    const widgets = ref<
      | AgWidgetsConfig
      | ((widgets: AgWidgetsConfig<AgDefaultRegistry>) => AgWidgetsConfig)
    >((config: AgWidgetsConfig) => {
      const existingGridDef = config.widgets.find(
        ({ id }) => id === "grid",
      ) as AgBaseWidgetDefinition<"grid", AgGridWidget>;
      const newGridDef: Pick<
        AgBaseWidgetDefinition<"grid", AgGridWidget>,
        "id" | "label" | "form"
      > = {
        id: "grid",
        label: "Grid",
        form: (params) => {
          // update the grid form to remove the widget type selector
          const oldTabGroup = existingGridDef.form(params) as AgFormTabGroup<
            AgPath<AgGridWidget>
          >;
          const [oldSetupTab, oldFormatTab] = oldTabGroup.items;
          const newSetupTab = {
            ...oldSetupTab,
            items: [...oldSetupTab.items.slice(1), oldSetupTab.items[0]],
          };
          return {
            ...oldTabGroup,
            items: [newSetupTab, oldFormatTab],
          };
        },
      } as const;
      return createWidgets({
        overrides: [newGridDef],
      });
    });
    const data = ref<AgDataSourcesDefinition | AgDataEngine>(null);

    const onApiReady = (params: AgStudioApiReadyEvent) => {
      studioApi.value = params.api;

      const getData = (data) => ({ sources: [{ id: "medals", data }] });

      fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
        .then((resp) => resp.json())
        .then((respData) => (data.value = getData(respData)));
    };

    return {
      studioApi,
      initialState,
      mode,
      widgets,
      data,
      onApiReady,
    };
  },
});

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

[Live example: Change the Configuration for Individual Widgets](https://www.ag-grid.com/studio/examples/widget-configuration/configure-individual-widgets/vue3/)

The example above changes the configuration for the Table widget to update the label from 'Table' to 'Grid', and move the widget selection input to the bottom of the setup tab.

```ts
<ag-studio
    :widgets="widgets"
    /* other studio properties ... */>
</ag-studio>

this.widgets = createWidgets({
    overrides: [
        {
            id: 'grid',
            label: 'Grid',
            // ... other overrides
        }
    ]
});
```

See the [Widget Configuration API](#widget-configuration-api) below for details on the `createWidgets` helper function.

## Pre-Configured Widgets

#### Pre-Configured Widgets

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgStudio } from "ag-studio-vue3";
import {
  AgBaseRegistry,
  AgBaseWidgetDefinition,
  AgColumnChartGrouped,
  AgDataEngine,
  AgDataSourcesDefinition,
  AgDefaultRegistry,
  AgReportState,
  AgSortConfig,
  AgStudioApi,
  AgStudioApiReadyEvent,
  AgStudioMode,
  AgStudioProperties,
  AgWidgetFieldReference,
  AgWidgetsConfig,
  createWidgets,
} from "ag-studio";

interface CustomColumnChart<TType extends string> extends Omit<
  AgColumnChartGrouped,
  "type"
> {
  type: TType;
}
interface MyRegistry extends AgBaseRegistry {
  widgets: readonly (
    | CustomDef1
    | CustomDef2
    | AgBaseWidgetDefinition<"column-chart-grouped", AgColumnChartGrouped>
  )[];
}

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div style="display: flex; flex-direction: column; height: 100%">
      <ag-studio
        style="width: 100%; height: 100%;"
        class="my-studio-container"
        @api-ready="onApiReady"
        :initialState="initialState"
        :widgets="widgets"
        :mode="mode"
        :data="data"></ag-studio>
      </div>
        </div>
    `,
  components: {
    "ag-studio": AgStudio,
  },
  setup(props) {
    const studioApi = shallowRef<AgStudioApi<MyRegistry> | null>(null);
    const initialState = ref<AgReportState<MyRegistry>>({
      pages: [
        {
          id: "a",
        },
      ],
      selectedPageId: "a",
      panels: {
        filters: {
          collapsed: true,
        },
        data: {
          collapsed: true,
        },
      },
    });
    const widgets = ref<
      | AgWidgetsConfig<MyRegistry>
      | ((
          widgets: AgWidgetsConfig<AgDefaultRegistry>,
        ) => AgWidgetsConfig<MyRegistry>)
    >((config: AgWidgetsConfig<AgDefaultRegistry>) => {
      const existingColumnChartDef = config.widgets.find(
        ({ id }) => id === "column-chart-grouped",
      ) as AgBaseWidgetDefinition<"column-chart-grouped", AgColumnChartGrouped>;
      // only show the widget type selector
      const form: CustomDef1["form"] = (params) => ({
        type: "tab-group",
        key: "config",
        items: [
          {
            type: "tab",
            key: "setup",
            label: "widgetFormSectionSetup",
            items: [params.createWidgetSection()],
          },
        ],
      });
      const def1: CustomDef1 = {
        ...existingColumnChartDef,
        id: "pre-configured-column-chart-1",
        label: "Gold Chart",
        defaultState: {
          dataMapping: {
            categoryKey: [{ id: "medals.country" }],
            valueKey: [
              {
                id: "medals.gold",
                aggregation: "sum",
              },
            ],
          },
          sort: [
            {
              field: { id: "medals.gold", aggregation: "sum" },
              direction: "desc",
            },
          ],
          format: {
            title: {
              enabled: true,
              text: "Gold Medals by Country",
            },
          },
        },
        form,
        formatShape: undefined,
        extends: "column-chart-grouped",
      };
      const def2: CustomDef2 = {
        ...existingColumnChartDef,
        id: "pre-configured-column-chart-2",
        label: "Silver Chart",
        defaultState: {
          dataMapping: {
            categoryKey: [{ id: "medals.country" }],
            valueKey: [
              {
                id: "medals.silver",
                aggregation: "sum",
              },
            ],
          },
          sort: [
            {
              field: { id: "medals.silver", aggregation: "sum" },
              direction: "desc",
            },
          ],
          format: {
            title: {
              enabled: true,
              text: "Silver Medals by Country",
            },
          },
        },
        form,
        formatShape: undefined,
        extends: "column-chart-grouped",
      };
      return createWidgets<MyRegistry>({
        menu: [
          {
            label: "Pre-Configured",
            widgetIds: [
              "pre-configured-column-chart-1",
              "pre-configured-column-chart-2",
            ],
          },
          {
            label: "Existing",
            widgetIds: ["column-chart-grouped"],
          },
        ],
        additionalTypes: [def1, def2],
      });
    });
    const mode = ref<AgStudioMode>("edit");
    const data = ref<AgDataSourcesDefinition | AgDataEngine>(null);

    const onApiReady = (params: AgStudioApiReadyEvent) => {
      studioApi.value = params.api;

      const getData = (data) => ({ sources: [{ id: "medals", data }] });

      fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
        .then((resp) => resp.json())
        .then((respData) => (data.value = getData(respData)));
    };

    return {
      studioApi,
      initialState,
      widgets,
      mode,
      data,
      onApiReady,
    };
  },
});

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

[Live example: Pre-Configured Widgets](https://www.ag-grid.com/studio/examples/widget-configuration/preconfigured-widgets/vue3/)

The example above updates the widget configuration to have two pre-configured widgets. These re-use the existing grouped column chart widgets, but set the fields and title, and hide all of the form options except for the widget selection input.

The pre-configured widgets are set up in a similar way to [Implementing a Custom Widget](https://www.ag-grid.com/studio/vue/custom-widgets#implementing-a-custom-widget), but they copy the existing grouped column chart widget definition.

The `extends` property is set to `'column-chart-grouped'` so that all of the default values are set correctly, and the `defaultState` property is set with the desired data mapping, sort and title details.

## Custom Widgets

To create your own widgets for AG Studio, see the [Custom Widgets](https://www.ag-grid.com/studio/vue/custom-widgets/) documentation.

## Widget Configuration API

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `widgets` | `AgWidgetsConfig<TRegistry> \| ((widgets: AgWidgetsConfig<AgDefaultRegistry>) => AgWidgetsConfig<TRegistry>)` |  | Configure widgets: - Add custom widgets - Override provided widgets - Change displayed widgets - Change default widget type when dragging fields |

Widget configuration is set using the `widgets` property. The easiest way to provide configuration is using the `createWidgets(params)` helper function, where `params` are of type `AgCreateWidgetsParams`:

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `menu` | `AgWidgetMenuGroup<TRegistry>[]` |  | Configures the widget menu that is displayed in the widgets tab in the edit panel, and the widget selection input. |
| `overrides` | `ExtractOverride<AgWidgetRegistry<TRegistry>>[]` |  | Overrides to the default widgets. |
| `defaultType` | `AgWidgetType<TRegistry>` |  | The default widget type created when dragging fields into the layout. |

## Widget Toolbar Actions

Each widget has a toolbar containing buttons that trigger various actions.

To customise the toolbar, follow the steps for [Changing the Configuration for Individual Widgets](#change-the-configuration-for-individual-widgets) and set the `toolbar` property.

The following actions are available by default:

| Action | ID | Widgets |
| --- | --- | --- |
| Duplicate widget | `'duplicate'` | All |
| Delete widget | `'delete'` | All |
| CSV export | `'export'` | Grid and chart widgets |
| Download as image | `'download'` | Chart widgets |

Actions can also be executed via the API method `performWidgetAction`.

| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `performWidgetAction` | `Function` |  | Execute an action for a widget. Action can be one of the default actions (`'duplicate'` or `'delete'`), or an action specific to that widget. |

#### Pre-Configured Widgets

```ts
import {
  createApp,
  defineComponent,
  onBeforeMount,
  ref,
  shallowRef,
} from "vue";
import { AgStudio } from "ag-studio-vue3";
import {
  AgDataEngine,
  AgDataSourcesDefinition,
  AgReportState,
  AgStudioApi,
  AgStudioApiReadyEvent,
  AgStudioMode,
  AgStudioProperties,
} from "ag-studio";

const VueExample = defineComponent({
  template: `
        <div style="height: 100%">
                <div style="display: flex; flex-direction: column; height: 100%">
      <div class="example-controls">
        <div class="controls-row">
          <button v-on:click="exportWidget()">Export Widget to CSV</button>
        </div>
      </div>
      <ag-studio
        style="width: 100%; height: 100%;"
        class="my-studio-container"
        @api-ready="onApiReady"
        :initialState="initialState"
        :mode="mode"
        :data="data"></ag-studio>
      </div>
        </div>
    `,
  components: {
    "ag-studio": AgStudio,
  },
  setup(props) {
    const studioApi = shallowRef<AgStudioApi | null>(null);
    const initialState = ref<AgReportState>({
      pages: [
        {
          id: "a",
          widgets: {
            "1": {
              type: "grid",
              dataMapping: {
                cols: [
                  { id: "medals.country" },
                  { id: "medals.sport" },
                  { id: "medals.gold", aggregation: "sum" },
                  { id: "medals.silver", aggregation: "sum" },
                  { id: "medals.bronze", aggregation: "sum" },
                  { id: "medals.total", aggregation: "sum" },
                ],
              },
              format: {
                title: {
                  text: "Medals by Country and Sport",
                },
              },
            },
            "2": {
              type: "column-chart-grouped",
              dataMapping: {
                categoryKey: [{ id: "medals.country" }],
                valueKey: [
                  { id: "medals.gold", aggregation: "sum" },
                  { id: "medals.silver", aggregation: "sum" },
                  { id: "medals.bronze", aggregation: "sum" },
                ],
                tooltipKey: [],
              },
            },
          },
          widgetLayout: {
            "1": {
              xTrack: 0,
              yTrack: 0,
              xSpan: 24,
              ySpan: 16,
            },
            "2": {
              xTrack: 0,
              yTrack: 16,
              xSpan: 24,
              ySpan: 16,
            },
          },
        },
      ],
      selectedPageId: "a",
      panels: {
        filters: {
          collapsed: true,
        },
        data: {
          collapsed: true,
        },
        edit: {
          collapsed: true,
        },
      },
    });
    const mode = ref<AgStudioMode>("edit");
    const data = ref<AgDataSourcesDefinition | AgDataEngine>(null);

    function exportWidget() {
      studioApi.value!.performWidgetAction("1", "export");
    }
    const onApiReady = (params: AgStudioApiReadyEvent) => {
      studioApi.value = params.api;

      const getData = (data) => ({ sources: [{ id: "medals", data }] });

      fetch("https://www.ag-grid.com/studio/example-assets/olympic-winners.json")
        .then((resp) => resp.json())
        .then((respData) => (data.value = getData(respData)));
    };

    return {
      studioApi,
      initialState,
      mode,
      data,
      onApiReady,
      exportWidget,
    };
  },
});

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

[Live example: Pre-Configured Widgets](https://www.ag-grid.com/studio/examples/widget-configuration/widget-actions/vue3/)

The example above demonstrates exporting data for the first widget via the API when the button is clicked.

### CSV Export

When performing CSV export, values are formatted the same way as in the widget.

By default, exports are limited to **1,000 rows** by applying a limit on the related query. Set `maxExportRows` on `dataOptions` to change this.

```ts
<ag-studio
    :dataOptions="dataOptions"
    /* other studio properties ... */>
</ag-studio>

this.dataOptions = {
    maxExportRows: 5000,
};
```

> **Warning**
>
> `maxExportRows` supports `-1` for unlimited exports. Depending on the size of your data, you may get unexpected or undesired results, including but not limited to: memory, bandwidth or resource exhaustion.
