# Displaying Progress Indicators

Canonical page: https://www.adaptabletools.com/docs/ui-progress-indicator

- AdapTable makes it possible to display a Progress Indicator during a long-running operation

AdapTable allows developers to create **Progress Indicators** when an operation takes a significant time to run.

It is also possible to display [Custom Window Popups](https://www.adaptabletools.com/docs/ui-popup-windows/index.md) to display more general information

Developers can either simply provide the text to display and use AdapTable's default rendering, or can provide custom rendering which will be used instead.

Show and hide Progress Indicators via [User Interface API](https://www.adaptabletools.com/docs/technical-reference-ui/index.md#user-interface-api):

- `showProgressIndicator` — displays the indicator (default or custom rendering)
- `hideProgressIndicator` — closes the indicator

### Configuring the Progress Indicator

The [`ProgressIndicatorConfig`](https://www.adaptabletools.com/docs/reference/progressindicatorconfig.md) object is defined as follows:

| Property | Type | Description |
| --- | --- | --- |
| [delay](https://www.adaptabletools.com/docs/reference/progressindicatorconfig.md#delay) | `number` | Length of Delay |
| [frameworkComponent](https://www.adaptabletools.com/docs/reference/progressindicatorconfig.md#frameworkcomponent) | [`AdaptableFrameworkComponent`](https://www.adaptabletools.com/docs/reference/adaptableframeworkcomponent.md) | A React, Angular or Vue Framework component to use |
| [render](https://www.adaptabletools.com/docs/reference/progressindicatorconfig.md#render) | [`CustomRenderFunction`](https://www.adaptabletools.com/docs/reference/customrenderfunction.md) | Render function |
| [renderMode](https://www.adaptabletools.com/docs/reference/progressindicatorconfig.md#rendermode) | `'content' \| 'dialog'` | Determines whether custom component is rendered as &quot;content&quot; (inside window) or &quot;dialog&quot; (replacing window) |
| [text](https://www.adaptabletools.com/docs/reference/progressindicatorconfig.md#text) | `string` | Text to display |

As can be seen content is provided in one of 2 ways:

- in Framework versions of AdapTable, by using the `frameworkComponent` property
- in the vanilla (i.e. non-Framework) AdapTable version, by using the `render` property

The `renderMode` property determines how the custom component is rendered and can be one of 2 values:

- "content" (default) the content is placed inside the default Dialog together with a spinner
- "dialog": custom content completely replaces the Dialog

<!-- framework: vanilla -->
### Vanilla

### Providing a Progress Indicator

Provide `text` on [`ProgressIndicatorConfig`](https://www.adaptabletools.com/docs/reference/progressindicatorconfig.md) for AdapTable's default spinner and message. Omit `render` and `frameworkComponent`.

```ts
const config: ProgressIndicatorConfig = {
  text: 'This standard Progress Indicator will display for 5 seconds',
};
```

Supply a `render` function that returns HTML. It receives [`CustomRenderContext`](https://www.adaptabletools.com/docs/reference/customrendercontext.md) when you need lifecycle hooks (`phase`, `element`, `adaptableApi`).

- `renderMode: 'content'` (default) — custom HTML appears inside AdapTable's progress dialog together with the spinner
- `renderMode: 'dialog'` — your HTML replaces the default dialog entirely

Optional `delay` (milliseconds) defers showing the indicator until the operation has run for that long.

```ts [[1, 3, "render"], [2, 9, "renderMode"]]
const config: ProgressIndicatorConfig = {
  text: 'Custom Indicator',
  render: () =>
    '<div style="padding:10px"><b>Custom progress content</b></div>',
};

const dialogConfig: ProgressIndicatorConfig = {
  text: 'New Dialog',
  renderMode: 'dialog',
  render: () =>
    '<div style="padding:10px"><b>Fully custom dialog content</b></div>',
};
```

Call `showProgressIndicator` wherever you have `adaptableApi` — for example a [Custom Toolbar Button](https://www.adaptabletools.com/docs/ui-dashboard-custom-toolbars/index.md#providing-adaptable-buttons) `onClick` handler.

```tsx
onClick: (button, context) => {
  context.adaptableApi.userInterfaceApi.showProgressIndicator(config);
},
```

Call `hideProgressIndicator` when the long-running task finishes (the demo uses a 5-second timeout).

```tsx
setTimeout(() => {
  context.adaptableApi.userInterfaceApi.hideProgressIndicator();
}, 5000);
```

**Example: Displaying a Progress Indicator**

Display a Progress Indicator

- This example contains 3 Custom Toolbar Buttons that each open a Progress Indicator:
  - `Show Standard Progress Indicator` - displays the text it is given and uses the default AdapTable rendering
  - `Show Custom Progress Indicator` - displays using custom rendering that was supplied
  - `Show New Dialog Indicator` - displays using a replacement Dialog
- All 3 Progress Indicators display for 5 seconds (before being hidden via `hideProgressIndicator`)

- Click the 3 toolbar buttons to see the associated Progress Indicators

Demo project (Vanilla); the files without a marker are shown below:

```text
src/
  adaptableOptions.ts
  agGridModules.ts     [template]
  columnDefs.ts        [template]
  gridOptions.ts       [template]
  index.ts             [template]
  onAdaptableReady.ts  [template]
  rowData.ts           [template]
  styles.css           [template]
index.html             [template]
package.json           [template]
tsconfig.json          [template]
```

Files marked `[template]` are the same in every demo; see the [demo template](https://www.adaptabletools.com/llms/demo-template.md#vanilla).

**`src/adaptableOptions.ts`**

```ts
import {
  AdaptableButton,
  AdaptableOptions,
  CustomRenderContext,
  CustomToolbarButtonContext,
  ProgressIndicatorConfig,
} from '@adaptabletools/adaptable';
import {WebFramework} from './rowData';

export const adaptableOptions: AdaptableOptions<WebFramework> = {
  primaryKey: 'id',
  adaptableId: 'Progress Indicator',
  dashboardOptions: {
    customToolbars: [
      {
        name: 'Buttons',
        title: 'Buttons',
        toolbarButtons: [
          {
            label: 'Show Standard Progress Indicator',
            buttonStyle: {
              variant: 'text',
              tone: 'info',
            },
            onClick: (
              button: AdaptableButton<CustomToolbarButtonContext>,
              context: CustomToolbarButtonContext
            ) => {
              const config: ProgressIndicatorConfig = {
                text: 'This standard Progress Indicator will display for 5 seconds',
              };
              context.adaptableApi.userInterfaceApi.showProgressIndicator(
                config
              );
              setTimeout(() => {
                context.adaptableApi.userInterfaceApi.hideProgressIndicator();
              }, 5000);
            },
          },
          {
            label: 'Show Custom Progress Indicator',
            buttonStyle: {
              variant: 'text',
              tone: 'warning',
            },
            onClick: (
              button: AdaptableButton<CustomToolbarButtonContext>,
              context: CustomToolbarButtonContext
            ) => {
              const config: ProgressIndicatorConfig = {
                text: 'Custom Indicator',
                render: (customRenderContext: CustomRenderContext) => {
                  return '<div style="height: 50px; width: 250px; background-color:lightyellow; color:red; padding:10px"><b><i>This Progess Indicator uses custom rendering and will display for 5 seconds</i></b></div>';
                },
              };
              context.adaptableApi.userInterfaceApi.showProgressIndicator(
                config
              );
              setTimeout(() => {
                context.adaptableApi.userInterfaceApi.hideProgressIndicator();
              }, 5000);
            },
          },
          {
            label: 'Show New Dialog Indicator',
            buttonStyle: {
              variant: 'text',
              tone: 'success',
            },
            onClick: (
              button: AdaptableButton<CustomToolbarButtonContext>,
              context: CustomToolbarButtonContext
            ) => {
              const config: ProgressIndicatorConfig = {
                text: 'New Dialog',
                renderMode: 'dialog',
                render: (customRenderContext: CustomRenderContext) => {
                  return '<div style="height: 50px; width: 250px; background-color:lightgreen; color:blue; padding:10px"><b><i>This Progess Indicator is a new dialog and will display for 5 seconds</i></b></div>';
                },
              };
              context.adaptableApi.userInterfaceApi.showProgressIndicator(
                config
              );
              setTimeout(() => {
                context.adaptableApi.userInterfaceApi.hideProgressIndicator();
              }, 5000);
            },
          },
        ],
      },
    ],
  },
  initialState: {
    Dashboard: {
      Tabs: [
        {
          Name: 'Messages',
          Toolbars: ['Buttons'],
        },
      ],
    },
    Theme: {CurrentTheme: 'dark'},
    Layout: {
      CurrentLayout: 'Standard Layout',
      Layouts: [
        {
          TableColumns: [
            'name',
            'language',
            'github_stars',
            'license',
            'has_projects',
            'has_pages',
            'created_at',
            'has_wiki',
            'updated_at',
            'pushed_at',
            'github_watchers',
            'week_issue_change',
          ],
          Name: 'Standard Layout',
          AutoSizeColumns: true,
        },
      ],
    },
  },
};
```

<!-- /framework -->

<!-- framework: angular -->
### Angular

### Providing a Custom Progress Indicator

Create a standard Angular Component for the indicator UI.

```ts
@Component({
  selector: 'progress-indicator',
  template: `
    <div class="progressIndicator">
      <div class="progressIndicator__spinner" aria-hidden="true"></div>
      <p class="progressIndicator__title">Loading market data</p>
      <p class="progressIndicator__message">
        Streaming quotes and positions — this demo closes after 5 seconds.
      </p>
    </div>
  `,
})
export class ProgressIndicator {
  constructor(@Inject(ADAPTABLE_API) private adaptableApi: AdaptableApi) {}
}
```

Create [`ProgressIndicatorConfig`](https://www.adaptabletools.com/docs/reference/progressindicatorconfig.md) and set `frameworkComponent`.

```tsx
const config: ProgressIndicatorConfig = {
  text: 'Loading market data',
  renderMode: 'content',
  frameworkComponent: {
    type: ProgressIndicator,
  },
};
```

Call `showProgressIndicator` on [`UserInterfaceApi`](https://www.adaptabletools.com/docs/reference/userinterfaceapi.md).

```tsx
adaptableApi.userInterfaceApi.showProgressIndicator(config);
```

On completion, call `hideProgressIndicator`.

```tsx
adaptableApi.userInterfaceApi.hideProgressIndicator();
```

**Example: Angular Components as Progress Indicators**

Providing Angular Components as Progress Indicators

- Progress Indicator using an Angular Framework Component, opened from a Dashboard Button

Demo project (Angular); the files without a marker are shown below:

```text
src/
  app/
    agGridModules.ts                 [template]
    app.component.ts
    app.module.ts
    columnDefs.ts                    [template]
    gridOptions.ts                   [template]
    onAdaptableReady.ts              [template]
    progress-indicator.component.ts
    rowData.ts                       [template]
    styles.css                       [template]
  index.html                         [template]
  main.ts                            [template]
  polyfills.ts                       [template]
package.json                         [template]
tsconfig.json                        [template]
```

Files marked `[template]` are the same in every demo; see the [demo template](https://www.adaptabletools.com/llms/demo-template.md#angular).

**`src/app/progress-indicator.component.ts`**

```ts
import {
  ADAPTABLE_API,
  AdaptableApi,
} from '@adaptabletools/adaptable-angular-aggrid';
import {Component, Inject} from '@angular/core';

@Component({
  standalone: false,
  selector: 'progress-indicator',
  template: `
    <div class="progressIndicator">
      <div class="progressIndicator__spinner" aria-hidden="true"></div>
      <p class="progressIndicator__title">Loading market data</p>
      <p class="progressIndicator__message">
        Streaming quotes and positions — this demo closes after 5 seconds.
      </p>
    </div>
  `,
  styles: [
    `
      .progressIndicator {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: calc(var(--ab-base-space) * 2);
        padding: calc(var(--ab-base-space) * 4);
        min-width: 280px;
        color: var(--ab-color-foreground, #333);
        background: var(--ab-color-background, #fff);
        border: 1px solid var(--ab-color-input-border, #ccc);
        border-radius: var(--ab-border-radius, 4px);
        box-shadow: var(--ab-shadow-sm);
      }

      .progressIndicator__spinner {
        width: 32px;
        height: 32px;
        border: 3px solid var(--ab-color-primarylight, #eee);
        border-top-color: var(--ab-color-accent, #07c);
        border-radius: 50%;
        animation: progressIndicatorSpin 0.8s linear infinite;
      }

      .progressIndicator__title {
        margin: 0;
        font-weight: 600;
        font-size: var(--ab-font-size-4, 1rem);
      }

      .progressIndicator__message {
        margin: 0;
        font-size: var(--ab-font-size-3, 0.875rem);
        text-align: center;
        opacity: 0.85;
      }

      @keyframes progressIndicatorSpin {
        to {
          transform: rotate(360deg);
        }
      }
    `,
  ],
})
export class ProgressIndicator {
  constructor(@Inject(ADAPTABLE_API) private adaptableApi: AdaptableApi) {}
}
```

**`src/app/app.module.ts`**

```ts
import {BrowserModule} from '@angular/platform-browser';
import {NgModule} from '@angular/core';

import {AgGridModule} from 'ag-grid-angular';
import {AdaptableAngularAgGridModule} from '@adaptabletools/adaptable-angular-aggrid';
import {AppComponent} from './app.component';
import {ProgressIndicator} from './progress-indicator.component';

@NgModule({
  declarations: [AppComponent, ProgressIndicator],
  imports: [BrowserModule, AgGridModule, AdaptableAngularAgGridModule],
  providers: [],
  bootstrap: [AppComponent],
  // @ts-ignore FIXME #AFL required only for Codesandbox (which uses an old rendering engine), since Ivy (Angular >9) 'entryComponents' is no longer required in standalone apps
  entryComponents: [ProgressIndicator],
})
export class AppModule {}
```

**`src/app/app.component.ts`**

```ts
import {Component} from '@angular/core';

import {
  AdaptableReadyInfo,
  AdaptableOptions,
  AdaptableButton,
  DashboardButtonContext,
  ProgressIndicatorConfig,
} from '@adaptabletools/adaptable-angular-aggrid';
import {GridOptions} from 'ag-grid-enterprise';

// Adaptable styles
import '@adaptabletools/adaptable-angular-aggrid/index.css';

// AG Grid styles
import './styles.css';

// grid configuration
import {gridOptions} from './gridOptions';
import {agGridModules} from './agGridModules';
import {onAdaptableReady} from './onAdaptableReady';
import {WebFramework} from './rowData';

import {ProgressIndicator} from './progress-indicator.component';

@Component({
  standalone: false,
  selector: 'app-root',
  template: `
    <div id="demoOutputAbove"></div>
    <adaptable-provider
      [adaptableOptions]="adaptableOpts"
      [gridOptions]="agGridOptions"
      [modules]="modules"
      (adaptableReady)="adaptableReady($event)"
      style="height: 100vh; width: 100vw;">
      <adaptable-ui style="flex: none"></adaptable-ui>
      <ag-grid-angular
        *adaptable="let adaptable"
        [gridOptions]="adaptable.gridOptions"
        [modules]="adaptable.modules"
        style="flex: 1">
      </ag-grid-angular>
    </adaptable-provider>
    <div id="demoOutputBelow"></div>
  `,
  styles: [
    `
      :host {
        height: 100vh;
        display: flex;
        flex-flow: column;
      }
    `,
  ],
})
export class AppComponent {
  adaptableOpts: AdaptableOptions<WebFramework> = {
    primaryKey: 'id',
    adaptableId: 'Angular Custom Progress Indicator',
    stateOptions: {loadState: () => Promise.resolve({})},
    dashboardOptions: {
      customDashboardButtons: [
        {
          label: 'Show Custom Progress Indicator',
          buttonStyle: {
            variant: 'outlined',
            tone: 'accent',
          },
          onClick: (
            _button: AdaptableButton<DashboardButtonContext>,
            context: DashboardButtonContext
          ) => {
            const config: ProgressIndicatorConfig = {
              text: 'Loading market data',
              renderMode: 'content',
              frameworkComponent: {
                type: ProgressIndicator,
              },
            };
            context.adaptableApi.userInterfaceApi.showProgressIndicator(config);
            setTimeout(() => {
              context.adaptableApi.userInterfaceApi.hideProgressIndicator();
            }, 5000);
          },
        },
      ],
    },
    initialState: {
      Theme: {CurrentTheme: 'dark'},
      Layout: {
        CurrentLayout: 'Standard Layout',
        Layouts: [
          {
            Name: 'Standard Layout',
            TableColumns: [
              'name',
              'language',
              'github_stars',
              'license',
              'created_at',
              'has_wiki',
              'updated_at',
              'pushed_at',
              'github_watchers',
              'description',
              'open_issues_count',
              'closed_issues_count',
              'open_pr_count',
              'closed_pr_count',
              'has_projects',
              'has_pages',
              'week_issue_change',
            ],
            AutoSizeColumns: true,
          },
        ],
      },
    },
  };
  agGridOptions: GridOptions<WebFramework> = gridOptions;
  modules = agGridModules;

  adaptableReady($event: AdaptableReadyInfo) {
    onAdaptableReady($event);
  }
}
```



<!-- /framework -->

<!-- framework: react -->
### React

### Providing a Custom Progress Indicator

Create a standard React component for the indicator UI.

```tsx
export const ProgressIndicator = () => {
  return (
    <div className="progressIndicator">
      <div className="progressIndicator__spinner" aria-hidden="true" />
      <p className="progressIndicator__title">Loading market data</p>
      <p className="progressIndicator__message">
        Streaming quotes and positions — this demo closes after 5 seconds.
      </p>
    </div>
  );
};
```

Create [`ProgressIndicatorConfig`](https://www.adaptabletools.com/docs/reference/progressindicatorconfig.md) and set `frameworkComponent`.

```tsx
const config: ProgressIndicatorConfig = {
  text: 'Loading market data',
  renderMode: 'content',
  frameworkComponent: () => {
    return <ProgressIndicator />;
  },
};
```

Call `showProgressIndicator` on [`UserInterfaceApi`](https://www.adaptabletools.com/docs/reference/userinterfaceapi.md).

```tsx
adaptableApi.userInterfaceApi.showProgressIndicator(config);
```

Call `hideProgressIndicator` when the operation completes.

```tsx
adaptableApi.userInterfaceApi.hideProgressIndicator();
```

**Example: React Components as Progress Indicators**

Providing React Components as Progress Indicators

- Progress Indicator using a React Framework Component, opened from a Dashboard Button

Demo project (React); the files without a marker are shown below:

```text
src/
  agGridModules.ts       [template]
  App.tsx
  columnDefs.ts          [template]
  gridOptions.ts         [template]
  index.tsx              [template]
  onAdaptableReady.ts    [template]
  ProgressIndicator.tsx
  rowData.ts             [template]
  styles.css             [template + shown below]
package.json             [template]
tsconfig.json            [template]
```

Files marked `[template]` are the same in every demo; see the [demo template](https://www.adaptabletools.com/llms/demo-template.md#react).

**`src/App.tsx`**

```ts
import * as React from 'react';
import {useState} from 'react';
import {
  Adaptable,
  AdaptableApi,
  AdaptableButton,
  AdaptableOptions,
  AdaptableReadyInfo,
  DashboardButtonContext,
  ProgressIndicatorConfig,
} from '@adaptabletools/adaptable-react-aggrid';

import {GridOptions} from 'ag-grid-enterprise';

// import adaptable css
import '@adaptabletools/adaptable-react-aggrid/index.css';
// import aggrid themes (using Balham theme)

import './styles.css';

import {onAdaptableReady} from './onAdaptableReady';
import {gridOptions} from './gridOptions';
import {agGridModules} from './agGridModules';
import {ProgressIndicator} from './ProgressIndicator';
import {WebFramework} from './rowData';

const App: React.FunctionComponent = () => {
  const adaptableApiRef = React.useRef<AdaptableApi>(null);

  const [adaptOptions, setAdaptOptions] = useState<
    AdaptableOptions<WebFramework>
  >({
    primaryKey: 'id',
    adaptableId: 'React Custom Progress Indicator',
    stateOptions: {loadState: () => Promise.resolve({})},
    dashboardOptions: {
      customDashboardButtons: [
        {
          label: 'Show Custom Progress Indicator',
          buttonStyle: {
            variant: 'outlined',
            tone: 'accent',
          },
          onClick: (
            button: AdaptableButton<DashboardButtonContext>,
            context: DashboardButtonContext
          ) => {
            const config: ProgressIndicatorConfig = {
              text: 'Loading market data',
              renderMode: 'content',
              frameworkComponent: () => {
                return <ProgressIndicator />;
              },
            };
            context.adaptableApi.userInterfaceApi.showProgressIndicator(config);
            setTimeout(() => {
              context.adaptableApi.userInterfaceApi.hideProgressIndicator();
            }, 5000);
          },
        },
      ],
    },
    initialState: {
      Theme: {CurrentTheme: 'dark'},
      Layout: {
        CurrentLayout: 'Standard Layout',
        Layouts: [
          {
            Name: 'Standard Layout',
            TableColumns: [
              'name',
              'language',
              'github_stars',
              'topics',
              'license',
              'created_at',
              'has_wiki',
              'updated_at',
              'pushed_at',
              'github_watchers',
              'description',
              'open_issues_count',
              'closed_issues_count',
              'open_pr_count',
              'closed_pr_count',
              'has_projects',
              'has_pages',
              'week_issue_change',
            ],
            AutoSizeColumns: true,
          },
        ],
      },
    },
  });
  const [agGridOptions, setAgGridOptions] = useState<GridOptions>(gridOptions);

  return (
    <div style={{display: 'flex', flexFlow: 'column', height: '100vh'}}>
      <div id="demoOutputAbove"></div>
      <Adaptable.Provider
        gridOptions={agGridOptions}
        adaptableOptions={adaptOptions}
        modules={[...agGridModules]}
        onAdaptableReady={(adaptableReadyInfo: AdaptableReadyInfo) => {
          // save a reference to adaptable api
          adaptableApiRef.current = adaptableReadyInfo.adaptableApi;
          onAdaptableReady(adaptableReadyInfo);
        }}>
        <Adaptable.UI style={{flex: 'none'}} />
        <Adaptable.AgGridReact />
      </Adaptable.Provider>
      <div id="demoOutputBelow"></div>
    </div>
  );
};
export default App;
```

**`src/ProgressIndicator.tsx`**

```ts
import * as React from 'react';

export const ProgressIndicator = () => {
  return (
    <div className="progressIndicator">
      <div className="progressIndicator__spinner" aria-hidden="true" />
      <p className="progressIndicator__title">Loading market data</p>
      <p className="progressIndicator__message">
        Streaming quotes and positions — this demo closes after 5 seconds.
      </p>
    </div>
  );
};
```

**`src/styles.css`**

```css
.progressIndicator {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(var(--ab-base-space) * 2);
  padding: calc(var(--ab-base-space) * 4);
  min-width: 280px;
  color: var(--ab-color-foreground, #333);
  background: var(--ab-color-background, #fff);
  border: 1px solid var(--ab-color-input-border, #ccc);
  border-radius: var(--ab-border-radius, 4px);
  box-shadow: var(--ab-shadow-sm);
}

.progressIndicator__spinner {
  width: 32px;
  height: 32px;
  border: 3px solid var(--ab-color-primarylight, #eee);
  border-top-color: var(--ab-color-accent, #07c);
  border-radius: 50%;
  animation: progressIndicatorSpin 0.8s linear infinite;
}

.progressIndicator__title {
  margin: 0;
  font-weight: 600;
  font-size: var(--ab-font-size-4, 1rem);
}

.progressIndicator__message {
  margin: 0;
  font-size: var(--ab-font-size-3, 0.875rem);
  text-align: center;
  opacity: 0.85;
}

@keyframes progressIndicatorSpin {
  to {
    transform: rotate(360deg);
  }
}
```



<!-- /framework -->

<!-- framework: vue -->
### Vue

### Providing a Custom Progress Indicator

Create a standard Vue component for the indicator UI.

```vue
<template>
  <div class="progressIndicator">
    <div class="progressIndicator__spinner" aria-hidden="true" />
    <p class="progressIndicator__title">Loading market data</p>
  </div>
</template>
```

Create [`ProgressIndicatorConfig`](https://www.adaptabletools.com/docs/reference/progressindicatorconfig.md) and set `frameworkComponent` using `h()`.

```tsx
const config: ProgressIndicatorConfig = {
  text: 'Loading market data',
  renderMode: 'content',
  frameworkComponent: () => h(ProgressIndicator),
};
```

Call `showProgressIndicator` on [`UserInterfaceApi`](https://www.adaptabletools.com/docs/reference/userinterfaceapi.md).

```tsx
adaptableApi.userInterfaceApi.showProgressIndicator(config);
```

Call `hideProgressIndicator` when the operation completes.

```tsx
adaptableApi.userInterfaceApi.hideProgressIndicator();
```

**Example: Vue Components as Progress Indicators**

Providing Vue Components as Progress Indicators

- Progress Indicator using a Vue Framework Component, opened from a Dashboard Button

Demo project (Vue); the files without a marker are shown below:

```text
public/
  index.html             [template]
src/
  agGridModules.ts       [template]
  App.vue
  columnDefs.ts          [template]
  gridOptions.ts         [template]
  main.ts                [template]
  onAdaptableReady.ts    [template]
  ProgressIndicator.vue
  rowData.ts             [template]
  shims-vue.d.ts         [template]
  styles.css             [template]
.babelrc                 [template]
package.json             [template]
tsconfig.json            [template]
```

Files marked `[template]` are the same in every demo; see the [demo template](https://www.adaptabletools.com/llms/demo-template.md#vue).

**`src/App.vue`**

```ts
<script setup lang="ts">
import {h} from 'vue';
import {
  AdaptableProvider,
  AdaptableAgGridVue,
  AdaptableUI,
  AdaptableOptions,
  AdaptableButton,
  DashboardButtonContext,
  ProgressIndicatorConfig,
} from '@adaptabletools/adaptable-vue3-aggrid';

import {onAdaptableReady} from './onAdaptableReady';
import {gridOptions} from './gridOptions';
import {agGridModules} from './agGridModules';
import {WebFramework} from './rowData';

import ProgressIndicator from './ProgressIndicator.vue';

const adaptableOpts: AdaptableOptions<WebFramework> = {
  primaryKey: 'id',
  adaptableId: 'Vue Custom Progress Indicator',
  stateOptions: {loadState: () => Promise.resolve({})},
  dashboardOptions: {
    customDashboardButtons: [
      {
        label: 'Show Custom Progress Indicator',
        buttonStyle: {
          variant: 'outlined',
          tone: 'accent',
        },
        onClick: (
          button: AdaptableButton<DashboardButtonContext>,
          context: DashboardButtonContext
        ) => {
          const config: ProgressIndicatorConfig = {
            text: 'Loading market data',
            renderMode: 'content',
            frameworkComponent: () => h(ProgressIndicator),
          };
          context.adaptableApi.userInterfaceApi.showProgressIndicator(config);
          setTimeout(() => {
            context.adaptableApi.userInterfaceApi.hideProgressIndicator();
          }, 5000);
        },
      },
    ],
  },
  initialState: {
    Theme: {CurrentTheme: 'dark'},
    Layout: {
      CurrentLayout: 'Standard Layout',
      Layouts: [
        {
          Name: 'Standard Layout',
          TableColumns: [
            'name',
            'language',
            'github_stars',
            'license',
            'created_at',
            'has_wiki',
            'updated_at',
            'pushed_at',
            'github_watchers',
            'description',
            'open_issues_count',
            'closed_issues_count',
            'open_pr_count',
            'closed_pr_count',
            'has_projects',
            'has_pages',
            'week_issue_change',
          ],
          AutoSizeColumns: true,
        },
      ],
    },
  },
};
</script>

<template>
  <AdaptableProvider
    :gridOptions="gridOptions"
    :adaptableOptions="adaptableOpts"
    :modules="agGridModules"
    @onAdaptableReady="onAdaptableReady">
    <div style="display: flex; flex-direction: column; height: 100vh">
      <AdaptableUI />
      <AdaptableAgGridVue style="flex: 1" />
    </div>
  </AdaptableProvider>
</template>
```

**`src/ProgressIndicator.vue`**

```ts
<script lang="ts">
export default {
  name: 'ProgressIndicator',
};
</script>

<template>
  <div class="progressIndicator">
    <div class="progressIndicator__spinner" aria-hidden="true" />
    <p class="progressIndicator__title">Loading market data</p>
    <p class="progressIndicator__message">
      Streaming quotes and positions — this demo closes after 5 seconds.
    </p>
  </div>
</template>

<style scoped>
.progressIndicator {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: calc(var(--ab-base-space) * 2);
  padding: calc(var(--ab-base-space) * 4);
  min-width: 280px;
  color: var(--ab-color-foreground, #333);
  background: var(--ab-color-background, #fff);
  border: 1px solid var(--ab-color-input-border, #ccc);
  border-radius: var(--ab-border-radius, 4px);
  box-shadow: var(--ab-shadow-sm);
}

.progressIndicator__spinner {
  width: 32px;
  height: 32px;
  border: 3px solid var(--ab-color-primarylight, #eee);
  border-top-color: var(--ab-color-accent, #07c);
  border-radius: 50%;
  animation: progressIndicatorSpin 0.8s linear infinite;
}

.progressIndicator__title {
  margin: 0;
  font-weight: 600;
  font-size: var(--ab-font-size-4, 1rem);
}

.progressIndicator__message {
  margin: 0;
  font-size: var(--ab-font-size-3, 0.875rem);
  text-align: center;
  opacity: 0.85;
}

@keyframes progressIndicatorSpin {
  to {
    transform: rotate(360deg);
  }
}
</style>
```



<!-- /framework -->
