# Action Column Buttons

Canonical page: https://www.adaptabletools.com/docs/handbook-action-column-button

- A `button` Control is a clickable button in an Action Column cell
- It is the same [Adaptable Button](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md) used in the Dashboard, Toolbars, Tool Panel and Forms
- `onClick` receives [`ActionColumnContext`](https://www.adaptabletools.com/docs/reference/actioncolumncontext.md)
- Optional `confirm` and async `busyLabel` cover prompts and pending state

The `button` Control is the most common Action Column Control.

Up to Version 24 it was the **only** control available in an Action Column

It is the same [Adaptable Button](https://www.adaptabletools.com/docs/ui-tutorial-displaying-adaptable-buttons/index.md) that appears throughout AdapTable — Dashboard buttons, Custom Toolbar buttons, Tool Panel buttons, and Form footer buttons.

The most important property is the `onClick` function which defines what happens when the button is clicked.

- `onClick` receives [`ActionColumnContext`](https://www.adaptabletools.com/docs/reference/actioncolumncontext.md)
- If the function returns a `Promise`, the button shows a pending state (optional `busyLabel`) until it resolves

The other properties are identical to a normal button: `label`, `icon`, `iconPosition` etc.

As with the AdapTable Button they can return or a static value or function that returns a value based on the row.

There is also a `style` property which is the same as the button's `buttonStyle` property (with `tone` & `variant`).

- The prop is `style` because lives on shared [`BaseControl`](https://www.adaptabletools.com/docs/reference/basecontrol.md) used by all Action Column Controls, not only buttons
- The type is still [`ButtonStyle`](https://www.adaptabletools.com/docs/reference/buttonstyle.md); handlers receive only the [`ActionColumnContext`](https://www.adaptabletools.com/docs/reference/actioncolumncontext.md) (no separate button argument)

There is an optional `confirm` which shows a prompt before the handler runs.

### Defining a Button Control

Put the Column in `actionColumnOptions.actionColumns`.

Supply `columnId` and an optional `friendlyName` (used as the header caption).

Each item in `controls` needs a `type`. For a button this is `'button'`.

`label` and `style` can be functions of the row — here they change when `Language` is _JavaScript_.

`onClick` receives the Action Column context and updates the row.

`hidden` and `disabled` are also functions of the context.

```ts [[1, 1, "actionColumnOptions"], [1, 2, "actionColumns"], [2, 4, "columnId"], [2, 5, "friendlyName"], [3, 8, "type"], [4, 9, "label"], [4, 13, "style"], [5, 17, "onClick"], [6, 27, "hidden"], [6, 30, "disabled"]]
actionColumnOptions: {
  actionColumns: [
    {
      columnId: 'update_stars',
      friendlyName: 'Update Stars',
      controls: [
        {
          type: 'button',
          label: (context) =>
            context.data.language === 'JavaScript'
              ? 'Add Star'
              : 'Remove Star',
          style: (context) =>
            context.data.language === 'JavaScript'
              ? {variant: 'raised', tone: 'accent'}
              : {variant: 'raised', tone: 'success'},
          onClick: (context) => {
            const increment =
              context.data.language === 'JavaScript' ? 1 : -1;
            context.adaptableApi.gridApi.setCellValue({
              columnId: 'github_stars',
              newValue: context.data.github_stars + increment,
              primaryKeyValue: context.primaryKeyValue,
              rowNode: context.rowNode,
            });
          },
          hidden: (context) =>
            context.data.name === 'stencil' ||
            context.data.name === 'polymer',
          disabled: (context) =>
            context.data.github_watchers < 200,
        },
      ],
    },
  ],
},
```

**Example: Action Columns: Button**

Button Controls with row-aware label, style, hidden and disabled

- `Update Stars` increments or decrements `Github Stars`
  - `label` and `style` change when `Language` is _JavaScript_
  - `hidden` when the `Name` is _stencil_ or _polymer_
  - `disabled` if fewer than 200 `Github Watchers`
- `TS` is an icon-only button that opens the TypeScript site, hidden unless `Language` is _TypeScript_

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 {
  ActionColumnContext,
  AdaptableOptions,
  CellUpdateRequest,
} from '@adaptabletools/adaptable';
import {WebFramework} from './rowData';

export const adaptableOptions: AdaptableOptions<WebFramework> = {
  primaryKey: 'id',
  adaptableId: 'Action Column Button',
  actionColumnOptions: {
    actionColumns: [
      {
        columnId: 'update_stars',
        friendlyName: 'Update Stars',
        settings: {
          suppressMenu: true,
          resizable: false,
        },
        controls: [
          {
            type: 'button',
            label: (context: ActionColumnContext<WebFramework>) =>
              context.data?.language === 'JavaScript'
                ? 'Add Star'
                : 'Remove Star',
            style: (context: ActionColumnContext<WebFramework>) =>
              context.data?.language === 'JavaScript'
                ? {variant: 'raised', tone: 'accent'}
                : {variant: 'raised', tone: 'success'},
            onClick: (context: ActionColumnContext<WebFramework>) => {
              const increment =
                context.data?.language === 'JavaScript' ? 1 : -1;
              const cellUpdateRequest: CellUpdateRequest = {
                columnId: 'github_stars',
                newValue: (context.data?.github_stars ?? 0) + increment,
                primaryKeyValue: context.primaryKeyValue,
                rowNode: context.rowNode,
              };
              context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
            },
            hidden: (context: ActionColumnContext<WebFramework>) =>
              context.data?.name === 'stencil' ||
              context.data?.name === 'polymer',
            disabled: (context: ActionColumnContext<WebFramework>) =>
              (context.data?.github_watchers ?? 0) < 200,
          },
        ],
      },
      {
        columnId: 'more_typescript',
        friendlyName: 'TS',
        settings: {
          suppressMenu: true,
          suppressMovable: true,
          resizable: false,
        },
        controls: [
          {
            type: 'button',
            icon: {
              style: {height: 20, width: 20},
              src: 'https://upload.wikimedia.org/wikipedia/commons/4/4c/Typescript_logo_2020.svg',
            },
            onClick: () => {
              Object.assign(document.createElement('a'), {
                target: '_blank',
                href: 'https://www.typescriptlang.org/',
              }).click();
            },
            hidden: (context: ActionColumnContext<WebFramework>) =>
              context.data?.language !== 'TypeScript',
          },
        ],
      },
    ],
  },
  initialState: {
    Theme: {CurrentTheme: 'dark'},
    Layout: {
      CurrentLayout: 'Standard Layout',
      Layouts: [
        {
          Name: 'Standard Layout',
          TableColumns: [
            'name',
            'github_stars',
            'update_stars',
            'week_issue_change',
            'github_watchers',
            'language',
            'more_typescript',
            'license',
            'created_at',
            'has_wiki',
            'updated_at',
            'pushed_at',
          ],
          AutoSizeColumns: true,
        },
      ],
    },
  },
};
```

## Multiple Buttons

There is no limit on the number of Buttons (or other Controls) in one Column.

**Example: Action Columns: Multiple Buttons**

Two Button Controls in one Column

- `Update Issues` has `Up` and `Down` buttons that change `Issue Change`
- `Manage Row` is pinned right and uses `create` / `delete` [Commands](https://www.adaptabletools.com/docs/handbook-action-column-command/index.md) instead

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 {
  ActionColumnContext,
  AdaptableOptions,
  CellUpdateRequest,
} from '@adaptabletools/adaptable';
import {WebFramework} from './rowData';

const bumpIssueChange = (
  context: ActionColumnContext<WebFramework>,
  delta: number
) => {
  const cellUpdateRequest: CellUpdateRequest = {
    columnId: 'week_issue_change',
    newValue: (context.data?.week_issue_change ?? 0) + delta,
    primaryKeyValue: context.primaryKeyValue,
    rowNode: context.rowNode,
  };
  context.adaptableApi.gridApi.setCellValue(cellUpdateRequest);
};

export const adaptableOptions: AdaptableOptions<WebFramework> = {
  primaryKey: 'id',
  adaptableId: 'Action Columns Multiple Buttons',
  actionColumnOptions: {
    actionColumns: [
      {
        columnId: 'update_issues',
        friendlyName: 'Update Issues',
        controls: [
          {
            type: 'button',
            label: 'Up',
            style: {variant: 'outlined', tone: 'info'},
            onClick: context => bumpIssueChange(context, 1),
          },
          {
            type: 'button',
            label: 'Down',
            style: {variant: 'outlined', tone: 'warning'},
            onClick: context => bumpIssueChange(context, -1),
          },
        ],
      },
      {
        columnId: 'manage_row',
        friendlyName: 'Manage Row',
        controls: [
          {
            type: 'command',
            command: 'create',
            label: 'Add',
            style: {variant: 'raised', tone: 'neutral'},
          },
          {
            type: 'command',
            command: 'delete',
            label: 'Delete',
            style: {variant: 'outlined', tone: 'neutral'},
          },
        ],
      },
    ],
  },
  rowFormOptions: {
    autoHandle: true,
    disableInlineEditing: true,
    setPrimaryKeyValue: context => ({
      ...context.rowData,
      id: context.adaptableApi.gridApi.getRowCount() + 1,
    }),
  },
  initialState: {
    Theme: {CurrentTheme: 'dark'},
    Layout: {
      CurrentLayout: 'Standard Layout',
      Layouts: [
        {
          Name: 'Standard Layout',
          TableColumns: [
            'name',
            'week_issue_change',
            'update_issues',
            'github_watchers',
            'license',
            'language',
            'created_at',
            'has_wiki',
            'updated_at',
            'pushed_at',
            'topics',
            'description',
            'manage_row',
          ],
          ColumnPinning: {manage_row: 'right'},
          AutoSizeColumns: true,
        },
      ],
    },
  },
};
```
