Vue Embedded AnalyticsCustom Widgets

Version 3.0.0

Custom widgets add application-defined widgets to AG Studio, for cases the provided widgets do not cover.

The example above demonstrates a custom widget showing a single data value.

Creating a Custom Widget Copy Link

To provide a custom widget, implement the AgWidgetDefinition interface.

TWidgetType
Unique widget identifier (e.g., 'grid', 'value', 'column-chart-grouped').
string
Display label, or localisation key.
AgCustomIcon
Optional icon for widget display. One of:
  • string - an SVG string
  • { className: string } - A CSS class name
  • { url: string } - A URL to an SVG
  • dataMappingCopy Link
    AgDataMappingDefinitions<keyof TOut["dataMapping"] & string>
    Optional data mappings for the widget (if required). This defines the type of fields and how they are used by the widget.
    formatShapeCopy Link
    Function
    Optional format shape. The shape created by this function will be used for parsing the format configuration. If provided, format state will be passed through the parse() method before being loaded into Studio. If using AI, the shape is required, as it uses the schema.
    Function
    Form configuration using typed form builder.
    defaultStateCopy Link
    Partial<TOut>
    Optional default state. If provided, this will override the default values in the form. It also allows defaults to be set for the data mapping and sort.
    extendsCopy Link
    "value" | "grid" | "pivot-grid" | "column-chart-grouped" | "column-chart-stacked" | "column-chart-stacked-100" | "bar-chart-grouped" | "bar-chart-stacked" | "bar-chart-stacked-100" | "line-chart" | "area-chart" | "area-chart-stacked" | "area-chart-stacked-100" | "scatter-chart" | "bubble-chart" | "radar-line-chart" | "radar-area-chart" | "radial-column-chart" | "nightingale-chart" | "radial-bar-chart" | "pie-chart" | "donut-chart" | "funnel-chart" | "cone-funnel-chart" | "pyramid-chart" | "treemap-chart" | "sunburst-chart" | "radial-gauge" | "linear-gauge" | "button-filter" | "list-filter" | "date-filter" | "text" | "image" | "combo-chart-grouped-column-line" | "combo-chart-stacked-column-line"
    Optional default widget ID that this definition extends. Use this if overriding or pre-configuring one of the default widgets. This ensure that any values that no longer appear in the form are still correctly mapped / set to the right default value. For custom widgets, this should not be set.
    string | Component<AgWidgetParams<TOut>> | (new () => AgTypeScriptComponent<AgWidgetParams<TOut>>)
    Custom component Either: a string that matches a Vue custom component; a custom Vue component; or a custom TypeScript component class (no Vue; working directly with the DOM).
    defaultSizeCopy Link
    AgWidgetSize
    Default widget size when created.
    minSizeCopy Link
    AgWidgetSize
    Minimum widget size constraints.
    toolbarCopy Link
    (AgWidgetToolbarButton | AgDefaultWidgetAction)[]
    default: ['duplicate', 'delete']
    Optional toolbar configuration. Can be a built-in item ('delete' or 'duplicate') or a custom item. If the item provides an action, that will be performed, otherwise it will be dispatched as a 'toolbarAction' event to the widget. If providing a custom value, 'duplicate' and 'delete' must be provided if required.
    featureConfigCopy Link
    AgWidgetFeatureConfig
    Optional feature configuration.
    optionsCopy Link
    TOptions
    Optional options passed directly to widget.
    AgWidgetAiMetadata
    Optional structured AI metadata for this widget type.

    Custom widgets are provided to the widgets property, similar to the Available Widgets configuration.

    Provide the custom widget definitions to the createWidgets(params) helper function, and add them to the menu.

    Import createWidgets from ag-studio-vue3 rather than ag-studio, so that the Vue-specific widget defaults are applied.

    <ag-studio
        :widgets="widgets"
        /* other studio properties ... */>
    </ag-studio>
    
    this.widgets = (widgetConfig) => createWidgets<CustomRegistry>({
        additionalTypes: [customWidgetDefinition],
        menu: [
            ...widgetConfig.menu,
            {
                label: 'Custom',
                widgetIds: ['customWidget'],
            },
        ]
    });

    For the types to work correctly, the custom widgets should be defined in the Registry Type.

    interface CustomRegistry extends AgBaseRegistry {
        widgets: readonly (AgDefaultWidgetDefinition | CustomWidgetDefinition)[]
    }

    Form Copy Link

    The widget form configures the form displayed in the edit panel. The values from the form are passed in the widget params.

    See the Form Configuration page for more details.

    AI Integration Copy Link

    For a custom widget to work with AI, the formatShape and ai properties must be defined in the widget definition.

    The shape returned by formatShape is used to provide the AI with the schema for the format property of the widget, and to validate the format value the AI sets via state.

    Data Mapping Copy Link

    The dataMapping property defines the fields or fieldsets that are required to configure the widget, and the required relationships between them.

    For example, to configure a line chart, the data mapping might look like this:

    const dataMapping = {
        xAxisKey: {
            type: 'field', // Only a single field allowed
            // All types of value allowed
            supportedRoles: ['category', 'numeric', 'temporal'],
            requires: { cardinality: 'many' }, // Many values are accepted
            required: true, // Required field - widget cannot be displayed without it
            sort: true, // Show the sort menu
            aiDescription: 'Field for the x axis.', // Description when used with AI
        },
        yAxisKey: {
            type: 'fieldset', // Multiple fields allowed
            supportedRoles: ['numeric'], // Only numeric values allowed
            // For each `xAxisKey`, this must map to a single value
            requires: { per: 'dataMapping.xAxisKey', cardinality: 'one' },
            required: true, // Required field - widget cannot be displayed without it
            sort: true, // Show the sort menu
            // Description when used with AI
            aiDescription: 'Field(s) for the y axis. Each field becomes a separate series.',
        },
    };

    A widget does not have to rely on a data mapping to choose its fields. See Reading the Report Schema.

    Widget Component Copy Link

    The custom component is a Vue component that receives params of type AgWidgetParams, and has a refresh(params) method that is called when the params are updated.

    Custom Widget Params Copy Link

    Studio API.
    contextCopy Link
    TContext
    Application context as set on context Studio property.
    widgetIdCopy Link
    string
    Widget ID.
    widgetTypeCopy Link
    string
    Widget type.
    formatCopy Link
    TWidget["format"]
    Widget format as constructed from the widget form.
    dataMappingCopy Link
    AgWidgetDataMapping<TWidget>
    Widget data mapping values.
    AgWidgetSort[] | undefined
    Widget sort if defined.
    configCopy Link
    AgWidgetConfig<TWidget, TOptions>
    Widget configuration.
    widgetApiCopy Link
    AgWidgetApi
    Widget API. Provides access to retrieve data.

    Display State Copy Link

    Widgets have four different display states that can be set via widgetApi.setDisplayState(state, metadata?). These will trigger different overlays to be displayed by the layout on top of the widget. The states are:

    • displayed - The widget has data and is ready to display. Studio will show no overlay; the widget is rendered normally.
    • loading - The widget is loading. Metadata defaults to { prominent: true } for a solid loading overlay; use { prominent: false } for an unobtrusive refresh indicator that keeps the previous content visible.
    • noData - The widget has no data (e.g. everything is filtered out or the data is empty). Studio will show an overlay with "No data to display".
    • incompleteDataMapping - The widget does not have all of the required fields set. Studio will show an overlay with the field selection inputs.

    Each time the widget updates, set the relevant status as needed.

    widgetApi.setDisplayState('loading');
    const response = await widgetApi.getData(request);
    // ... process the response
    widgetApi.setDisplayState('displayed');

    Loading Data Copy Link

    Data is loaded via widgetApi.getData(request). The request can be constructed from the data mapping values in the params.

    "flat"
    Flat row query. Omit for backwards compatibility.
    fieldsCopy Link
    AgWidgetField[]
    List of fields to return in the query. Unaggregated fields will automatically be used for grouping.
    AgSort[]
    Sort the result based on the provided fields.
    filterCopy Link
    AgFilter[]
    Additional filter to apply. Page-level filters and widget-level filters (including from filter widgets and cross filters) will be automatically applied.
    AgLimit
    Limit the number of rows returned, or for pagination.

    If the widget is making multiple independent data requests, then pass a second options argument to getData(request, options) where options contains a distinct query ID per request (e.g. { queryId: 'request1' }). Otherwise the later requests will cancel the earlier requests. If your widget only makes one data request (per call to refresh), this is not required.

    Reading the Report Schema Copy Link

    A widget does not have to rely on a data mapping to choose its fields. Call getSchema() on the widget API to list every table and field in the report's schema. Tables, and the fields within each table, come back in the order the data panel lists them.

    The example below defines a widget with no data mapping. It reads the schema, then shows a grid with one column per field.

    Popups Copy Link

    If a custom widget creates its own popup that is anchored outside of the custom widget DOM element (e.g. like a third-party date picker), then the popup element needs to have the 'ag-custom-component-popup' CSS class. This allows Studio to determine correctly when focus is within a widget.

    Cross-Filtering Copy Link

    To implement cross-filtering from within a custom widget, the cross filter methods can be used from the widget API.

    toggleCrossFilterCopy Link
    Function
    Set a cross filter.
    resetCrossFilterCopy Link
    Function
    Clear cross filter.
    getCrossFilterSelectionsCopy Link
    Function
    Get the current cross filter for this widget.

    Every selection belongs to a group, a zero-based number identifying which of the widget's selections is being set. A widget holds one selection per group, and selections in different groups are independent of each other. A widget that holds a single selection should pass group: 0; a widget that selects on several fields at once should give each field its own group.

    A widget that selects on several fields together - a sankey link or a matrix cell, where one click means "this channel and this product" - should use a multi value selection instead of a group per field. Each toggleCrossFilter call with type: 'multiValue' contributes one combination of field and value pairs; the pairs within a combination must all match, and a row is included when it matches any one of the combinations the selection holds. Toggling the same set of pairs again removes that combination.

    api.toggleCrossFilter({
        type: 'multiValue',
        values: [
            { field: channelField, value: 'Online' },
            { field: productField, value: 'Clothing' },
        ],
        group: 0,
    });

    To support the cross filter highlight behaviour (similar to some of the default charts, e.g. column charts), enable it in the widget definition.

     const widgetDefinition = {
        // ...
        featureConfig: {
            crossFilter: {
                supportsHighlight: true
            }
        }
     };

    When this is enabled, the data response will contain two datasets. The original data (response.results), and the cross-filtered data (response.crossFilter).

    AG Grid & AG Charts in Widgets Copy Link

    As well as the built-in AG Grid and AG Charts widgets, it is possible to create your own custom widgets using AG Grid and AG Charts.

    To match the AG Grid theming in Studio, use studioGridTheme and pass it to the theme grid option.

    For AG Charts, set the following in chart options (where api is the Studio API in the widget params):

    const chartOptions = {
        // ... other options
        theme: getChartTheme(api),
        background: {
            fill: 'transparent'
        }
    };

    Using AG Grid Enterprise or AG Charts Enterprise in a custom widget requires the relevant AG Grid Enterprise or AG Charts Enterprise licence.

    Custom Widget Examples Copy Link

    Sankey Chart Copy Link

    A Sankey diagram visualises flow between two sets of nodes, sized by a numeric measure. This example maps a sales dataset (channel → product category) alongside a bar chart of the same revenue measure.

    The widget takes no part in cross filtering: it requests its data with crossFilter: 'none', so the flow diagram always covers the whole dataset and its node set never reflows. For a custom widget that does cross filter, see the Custom Widget with Cross Filter example above.

    Choropleth Map Copy Link

    A choropleth map shades geographic regions by a numeric measure. This example renders UK county boundaries using AG Charts' map-shape series and supports click-to-cross-filter alongside a regional bar chart.

    The colour domain is clamped to the p10-p90 range of the dataset, preventing a single high-value region from compressing all other counties into a narrow band near the minimum. When counties are selected, a background layer renders the full distribution at reduced opacity to preserve geographic context.