# Header Menu & Header Buttons

#### Demo

**Header Button Plugin**

[Demo Page](https://ghiscoding.github.io/slickgrid-vue-demos/#/Example7) / [Demo Component](https://github.com/ghiscoding/slickgrid-universal/blob/master/demos/vue/src/components/Example7.vue)

**Header Menu Plugin**

[Demo Page](https://ghiscoding.github.io/slickgrid-vue-demos/#/Example8) / [Demo Component](https://github.com/ghiscoding/slickgrid-universal/blob/master/demos/vue/src/components/Example8.vue)

### Header Menu

The `Header Menu` is now part of `Slickgrid-Universal` and is enabled by default via the grid option "enableHeaderMenu" flag.

#### How to use it?

**It's Enabled by default**

Technically, it's enable by default and so you don't have anything to do to enjoy it. However if you want to customize the content of the Header Menu, then continue reading.

### Customization

#### Custom Commands

The Header Menu also comes, by default, with a list of built-in custom commands (all their `positionOrder` are in the reserved range of 40 to 60)

* Sort Ascending (you can hide it with `hideSortCommands: true`)
* Sort Descending (you can hide it with `hideSortCommands: true`)
* Hide Column (you can hide it with `hideColumnHideCommand: true`)

This section is called Custom Commands because you can also customize this section with your own commands. You can do this in two ways: using static command items or using a dynamic command list builder.

**Static Command Items**

To add static commands, fill in an array of items in your column definition's `header.menu.commandItems`. For example, `Slickgrid-Universal` is configured by default with these settings (you can overwrite any one of them):

```ts
gridOptions.value = {
  enableAutoResize: true,
  enableHeaderMenu: true,   // <<-- this will automatically add extra custom commands
  enableFiltering: true,
  headerMenu: {
    onCommand: (e, args) => {
      if (args.command === 'hide') {
        controlService.hideColumn(args.column);
        controlService.autoResizeColumns();
      } else if (args.command === 'sort-asc' || args.command === 'sort-desc') {
        // get previously sorted columns
        const cols: ColumnSort[] = sortService.getPreviousColumnSorts(args.column.id + '');

        // add to the column array, the column sorted by the header menu
        cols.push({ sortCol: args.column, sortAsc: (args.command === 'sort-asc') });
        sortService.onLocalSortChanged(gridObj, gridOptions, dataviewObj, cols);

        // update the gridObj sortColumns array which will at the same add the visual sort icon(s) on the UI
        const newSortColumns: ColumnSort[] = cols.map((col) => {
          return { columnId: col.sortCol.id, sortAsc: col.sortAsc };
        });
        gridObj.setSortColumns(newSortColumns); // add sort icon in UI
      } else {
        alert('Command: ' + args.command);
      }
    }
  }
};
```

**Dynamic Command List Builder**

For advanced use cases where you need to dynamically build the command list, use `commandListBuilder`. This callback receives the built-in commands and allows you to filter, sort, or modify the list before it's rendered in the UI, giving you full control over the final command list. This is executed **after** `commandItems` and is the **last call before rendering**.

```ts
columns.value = [
  {
    id: 'title',
    name: 'Title',
    field: 'title',
    header: {
      menu: {
        commandListBuilder: (builtInItems) => {
          // Append custom commands to the built-in sort/hide commands
          return [
            ...builtInItems,
            'divider',
            {
              command: 'freeze-column',
              title: 'Freeze Column',
              iconCssClass: 'mdi mdi-pin',
              action: (e, args) => {
                // Implement column freezing
                console.log('Freeze column:', args.column.name);
              }
            }
          ];
        }
      }
    }
  }
];
```

**Example: Conditional commands based on column type**

```ts
header: {
  menu: {
    commandListBuilder: (builtInItems) => {
      const column = this; // column context
      
      // Add filtering option only for filterable columns
      const extraCommands = [];
      if (column.filterable !== false) {
        extraCommands.push({
          command: 'clear-filter',
          title: 'Clear Filter',
          iconCssClass: 'mdi mdi-filter-remove',
          action: (e, args) => {
            filterService.clearFilterByColumnId(args.column.id);
          }
        });
      }
      
      return [...builtInItems, ...extraCommands];
    }
  }
}
```

**Example: Remove sort commands, keep only custom ones**

```ts
header: {
  menu: {
    commandListBuilder: (builtInItems) => {
      // Filter out sort commands
      const filtered = builtInItems.filter(item => 
        item !== 'divider' && 
        !item.command?.includes('sort')
      );
      
      // Add custom commands
      return [
        ...filtered,
        {
          command: 'custom-action',
          title: 'Custom Action',
          iconCssClass: 'mdi mdi-star',
          action: (e, args) => alert('Custom: ' + args.column.name)
        }
      ];
    }
  }
}
```

**When to use `commandListBuilder`:**

* You want to append/prepend items to built-in commands
* You need to filter or modify commands based on column properties
* You want to customize the command list per column dynamically
* You need full control over the final command list

**Note:** Use `commandListBuilder` **instead of** `commandItems`, not both together.

**Callback Hooks**

There are 2 callback hooks which are accessible in the Grid Options

* `onBeforeMenuShow`
* `onCommand`

For more info on all the available properties of the custom commands, you can read refer to the doc written in the Grid Menu [implementation](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/extensions/slickHeaderButtons.ts) itself.

#### Custom Menu Item Rendering

To customize the appearance of menu items with custom HTML, badges, icons, or interactive elements, you can use the `slotRenderer` or `defaultMenuItemRenderer` callbacks.

See [Custom Menu Slots](https://github.com/ghiscoding/slickgrid-universal/blob/master/frameworks/slickgrid-vue/docs/menu-slots.md) for detailed examples and best practices on rendering custom menu item content.

#### How to change icon(s) of the default commands?

You can change any of the default command icon(s) by changing the `icon[X-command]`, for example, see below for the defaults.

```ts
gridOptions.value = {
  enableHeaderMenu: true,
  headerMenu: {
    iconColumnHideCommand: 'mdi mdi-close'
    iconSortAscCommand: 'mdi mdi-sort-ascending'
    iconSortDescCommand: 'mdi mdi-sort-descending',
  },
};
```

#### How to Disable the Header Menu?

You can disable the Header Menu, by calling `enableHeaderMenu: false` from the Grid Options.

```ts
gridOptions = {
   enableHeaderMenu: false
};
```

#### How to Exclude Header Menu from a Particular Column?

You can exclude a column from getting a Header Menu by calling `excludeFromHeaderMenu` in your Column Definition. For example, we don't need it on a column that has an edit icon:

```ts
columns.value = [
  { id: 'edit', formatter: Formatters.editIcon, excludeFromHeaderMenu: true, excludeFromExport: true },
  { id: 'title', name: 'Title', field: 'title', sortable: true },
  { id: 'duration', name: 'Duration (days)', field: 'duration', sortable: true },
];
```

#### Sample

You can add Header Menu to 1 column or all columns like shown below. You can also add sub-menus by nesting `commandItems`

```ts
// add custom Header Menu to all columns except "Action"
columns.value.forEach(col => {
  col.header = {
    menu: {
      commandItems: [
        { command: 'sort-ascending', title: 'Sort Ascending' },
        { command: 'sort-descending', title: 'Sort Descending' },
        'divider',
        {
          // we can also have multiple nested sub-menus
          command: 'custom-actions', title: 'Hello', positionOrder: 99,
          commandItems: [
            { command: 'hello-world', title: 'Hello World' },
            { command: 'hello-slickgrid', title: 'Hello SlickGrid' },
            {
              command: 'sub-menu', title: `Let's play`, cssClass: 'green', subMenuTitle: 'choose your game', subMenuTitleCssClass: 'text-italic salmon',
              commandItems: [
                { command: 'sport-badminton', title: 'Badminton' },
                { command: 'sport-tennis', title: 'Tennis' },
                { command: 'sport-racquetball', title: 'Racquetball' },
                { command: 'sport-squash', title: 'Squash' },
              ]
            }
          ]
        }
      ]
    }
  };
});
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ghiscoding.gitbook.io/slickgrid-vue/grid-functionalities/header-menu-header-buttons.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
