# Migration Guide to 10.x (2026-03-02)

### Simplification, Modernization and Accessibility⚡

One of the biggest change of this release is to hide columns by using the `hidden` property (used by Column Picker, Grid Menu, etc...). Previously we were removing columns from the original columns array and then we were typically calling `setColumns()` to update the visible columns in the grid, but this meant that we had to keep references for all visible/non-visible columns. With this new release we now keep the full columns array at all time and simply change their visibility via the `hidden` prop by using `grid.updateColumnById('id', { hidden: true })` and finally we update the grid via `grid.updateColumns()`. Also, what I'm trying to emphasis is that you should avoid using `grid.setColumns()` in v10 and above but rather start toggling their `hidden` properties when you define them or dynamically change them in the future, see more details below\...

This new release also brings significant improvements to accessibility (a11y), making grids more usable for keyboard and screen reader users. For example, you can now use Tab/Shift+Tab to focus the Header Menu or Grid Menu, and then navigate menu commands with the arrow keys, making keyboard navigation much more intuitive and accessible.

**Major Changes - Quick Summary**

* [`hidden` columns](#hidden-columns)
* improvements to accessibility (see above)
* [What's next?](#whats-next-...version-11)

> **Note:** if you come from an earlier version, please make sure to follow each migrations in their respective order (review previous migration guides)

> **Tip:** An [agent skill guide](https://github.com/ghiscoding/slickgrid-universal/blob/master/docs/migrations/migration-to-10.x.skill.yaml) is available to help structure your migration. This provides a quick reference of all major changes, code examples, and migration checklists.

#### Column Definitions

**Hidden Columns**

*if you're not dynamically hiding columns and you're not using `colspan` or `rowspan` then you might not be impacted as much by this change.*

For years, I had to keep some references in a Shared Service as `shared.allColumns` and `shared.visibleColumns`, mostly for storing their position order and translating locales which are being used by Column Picker and Grid Menu to keep track of which columns to hide/show and in which order; then later we called `grid.setColumns()` to update the columns in the grid... but that had side effects since SlickGrid never kept the entire column definitions list (up until now). However with v10, we simply toggle the `hidden` property on the column(s) to hide/show any of them, with this release we now keep the full columns reference at all time. We can translate them more easily while keeping their original position and we no longer need to use `grid.setColumns()`, what we'll do instead is to start using `grid.updateColumnById('colId', { hidden: true })`. If you want to get visible columns, you can now just call `grid.getVisibleColumns()` which behind the scene is simply filtering `columns.filter(c => !c.hidden)`. This new approach does also come with new side effects for colspan/rowspan, because previously when we were hiding a column then the column to the right were previously taking over the spanning, but with the new approach, if we hide a column then its spanning will now disappear with the column (so I had to make code changes to handle that too)... If you want more details, you can see the full explanations of all the changes in [PR #2281](https://github.com/ghiscoding/slickgrid-universal/pull/2281)

**Summary Note** `grid.getColumns()` now includes hidden columns — code that assumed only visible columns will now need to filter with `!col.hidden` or simply switch to `grid.getVisibleColumns()` (see below).

**New Approach with column `hidden` property**

| Before                                                | After                                                                        |
| ----------------------------------------------------- | ---------------------------------------------------------------------------- |
| `grid.setColumns(visibleCols)`                        | `grid.updateColumnById('id', { hidden: true });` and `grid.updateColumns();` |
| `sharedService.allColumns`                            | `grid.getColumns()` *... is now including all columns*                       |
| `sharedService.visibleColumns` or `grid.getColumns()` | `grid.getVisibleColumns()`                                                   |

### Grid Functionalities

*following changes should be transparent to most users, I'm just listing them in case of side effects.*

1. Composite Editor Component, migrated from a `<div>` to a `<dialog>` to create the modal component. The dialog element is native code and it has better accessibility (aria) support with current baseline showing as "widely available". A fallback to `<div>` is also available in case `<dialog>` doesn't work for everybody (e.g. it doesn't work in Salesforce LWC, hence the available fallback)
2. Grid Menu, replace `calc(100% - 18px)` with CSS flexbox to position the Grid Menu button, which is a much better approach to properly align everything.

### Changes

#### Removed `@deprecated` code

*following changes should be transparent to most users*

1. `applyHtmlCode()` was removed and replaced with `applyHtmlToElement()`
2. Grid Option `throwWhenFrozenNotAllViewable` was removed and replaced with `invalidColumnFreezeWidthCallback`

#### Selection Models, keeping only `SlickHybridSelectionModel`

1. drop both `SlickCellSelectionModel`/`SlickRowSelectionModel` and keep only `SlickHybridSelectionModel`
2. drop both `enableHybridSelection`/`enableRowSelection` and merge them into a new `enableSelection` grid option
3. rename `rowSelectionOptions` grid option to `selectionOptions`

`SlickHybridSelectionModel` was previously introduced in order to merge and allow using both Cell/Row Selections separately and/or in combo on the same grid. It was introduced in v9.x for initial testing and after using it for a few months, it's now safe to drop the older `SlickCellSelectionModel` / `SlickRowSelectionModel` models and keep only the hybrid model (for smaller build & less code to maintain). Also, since we now have the Hybrid model and it's now accepting options for different selection models, I think it's better to rename `rowSelectionOptions` to `selectionOptions` since it now makes more sense with the hybrid approach and you will need to update your code when using Row Selection, see below:

```diff
gridOptions = {
- enableHybridSelection: true,
- enableRowSelection: true,
+ enableSelection: true,

- rowSelectionOptions: {
+ selectionOptions: {
    selectActiveRow: false,

    // optional type can be: ['cell','row','mixed'] defaults to 'mixed'
+   selectionType: 'mixed',
  }
};
```

**Internal icons CSS class changes**

I found that some of the internal icons were wrongly using the `mdi-` prefix and that is wrong and causes problems when creating new Themes that don't use the MDI icons. This mean that the following CSS classes were renamed. If you are using any of them for E2E tests or for styling reasons, then make sure to update them.

| before                    | after                     | component                 |
| ------------------------- | ------------------------- | ------------------------- |
| `mdi-icon-check`          | `sgi-icon-check`          | Row Selections            |
| `mdi-icon-partial-check`  | `sgi-icon-partial-check`  | Row Selections            |
| `mdi-icon-uncheck`        | `sgi-icon-uncheck`        | Row Selections            |
| `mdi-icon-picker-check`   | `sgi-icon-picker-check`   | Column Picker / Grid Menu |
| `mdi-icon-picker-uncheck` | `sgi-icon-picker-uncheck` | Column Picker / Grid Menu |

### New Features

#### Auto-Enabled External Resources

This change does not require any code change from the end user, but it is nonetheless a change to be aware of. The reason I decided to implement this one, is that I often forget myself to enable the associated resource flags and typically if you want to load the resource then it's probably because you want to use it, hence auto-enabling the resource(s) makes sense. For example, if your register `ExcelExportService` then the library will now auto-enable the resources with their associated flags (which in this case is `enableExcelExport:true`)... unless you have already enabled/disabled the flag yourself, then in that case the internal assignment will simply be skipped and yours will prevail. Also just to be clear, the list of auto-enabled external resources is rather small and so it will auto-enable the following resources:

* ExcelExportService → `enableExcelExport: true`
* PdfExportService → `enablePdfExport: true`
* TextExportService → `enableTextExport: true`
* CompositeEditorComponent → `enableCompositeEditor: true`
* RowDetailView → `enableRowDetailView: true`

#### Menu with Commands (slot renderer)

All menu plugins (Cell Menu, Context Menu, Header Menu and Grid Menu) now have a new UI feature `commandListBuilder: (items) => items` which is now allowing you to filter/sort and maybe override built-in commands rendering. With this new feature in place, I can deprecate all `hide...` properties and also `positionOrder` since you can now do this with the new builder. You could also use a new `hideCommands` which accepts an array of built-in command names. This will remove a large amount of `hide...` properties (about 30) that keeps increasing anytime a new built-in command gets added (in other words, this will simplify maintenance for both you and me).

The props above are currently tagged as deprecations in v10.x but it's strongly recommended to start using the new `commandListBuilder` and/or `hideCommands` to move away from the deprecated properties which will be removed in v11.x (next year). For example if we want to hide some built-in commands:

```diff
gridOptions = {
  gridMenu: {
    // @deprecated properties
-   hideExportCsvCommand: true,
-   hideTogglePreHeaderCommand: true,

    // hide via command name(s)
+   hideCommands: ['export-csv', 'toggle-preheader'],

    // or hide via builder
+   commandListBuilder: (cmdItems) => cmdItems.filter(x => x !== 'divider' && x.command !== 'export-csv' && x.command !== 'toggle-preheader')
  }
}
```

There's also a new Renderer similar to Slots but implemented with native code to make it cross-platform compatible. The usage is actually very similar to how you would use a cell Formatter. You can see a new [Example 40](https://ghiscoding.github.io/slickgrid-universal/#/example40) demoing this new feature and also the command builder mentioned above. Go to [Menu Slots documentation](https://ghiscoding.gitbook.io/slickgrid-universal/grid-functionalities/menu-slots) to read more about this new feature.

> There's also a new `columnListBuilder` which is similar to the other builder but for Columns, it can be useful as well to sort and/or filter columns.

**Menu Options `optionItems` (deprecated)**

Menu Options list, using `optionItems` are now deprecated and will be removed in next major v11. That is quite similar to Command List and barely anyone uses it, so let's remove it in v11 and just use `commandItems` instead (see [docs](https://ghiscoding.gitbook.io/slickgrid-universal/column-functionalities/cell-menu#default-usage) for both usages).

#### Tooltips Outside the Grid (new feature)

You can now use the custom tooltip plugin to display tooltips on elements outside the grid (e.g., buttons, dialogs, etc.) by enabling the `observeAllTooltips` option. This allows the plugin to observe elements anywhere in your page that have `title` or `data-slick-tooltip` attributes and provide the same UI look & feel across your project. See Custom Tooltip [documentation](https://ghiscoding.gitbook.io/slickgrid-universal/grid-functionalities/custom-tooltip)

**Enable Global Tooltip Observation**

```ts
this.gridOptions = {
  externalResources: [new SlickCustomTooltip()],
  customTooltip: {
    observeAllTooltips: true, // observe tooltips outside the grid (defaults to false)
    // observeTooltipContainer: 'body', // <-- you can also define where to observe (defaults to `body`)
  },
};
```

***

{% hint style="info" %}
**Info** the changes in the next few lines were all mentioned in the previous ["Migration Guide v9.0"](https://github.com/ghiscoding/slickgrid-universal/blob/master/docs/migrations/migration-to-9.x). So, if you have already made these changes then you could skip the section below **but** scroll down further to read the last section ["What's next? ...version 11?"](#whats-next-...version-11).
{% endhint %}

#### Interfaces / Enums changes

Removing most Enums and replacing them with string literal types (use `type` instead of `enum` because again `type` aren't transpiled and `enum` are). Making this change will help decrease the build size by transpiling a lot less code.

```diff
columns = [{
  id: 'age', ...
- type: FieldType.number,
+ type: 'number',
}];
```

Below is a list of Enums that you need to replace with their associated string literals. A suggestion is to do a Search on any of these group name prefixes, e.g.: `FieldType.` and replace them all

**Hint** You can use VSCode search & replace, but make sure it's set to Regular Expression search pattern

| Search (regex)             | Replace  |
| -------------------------- | -------- |
| `FieldType\.([a-z_]+)(.*)` | `'$1'$2` |

Below is an abbreviated list of Enums to update, make sure to update them all

| Enum Name          | from `enum`                    | to string `type`             | Note                                                                                                                                                      |
| ------------------ | ------------------------------ | ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `DelimiterType`    | `DelimiterType.comma`          | `','`                        |                                                                                                                                                           |
|                    | `DelimiterType.colon`          | `':'`                        |                                                                                                                                                           |
|                    | `DelimiterType.space`          | `' '`                        |                                                                                                                                                           |
| ...                | ...                            | ...                          |                                                                                                                                                           |
| `EventNamingStyle` | `EventNamingStyle.camelCase`   | `'camelCase'`                |                                                                                                                                                           |
|                    | `EventNamingStyle.kebabCase`   | `'kebabCase'`                |                                                                                                                                                           |
|                    | `EventNamingStyle.lowerCase`   | `'lowerCase'`                |                                                                                                                                                           |
| ...                | ...                            | ...                          |                                                                                                                                                           |
| `FieldType`        | `FieldType.boolean`            | `'boolean'`                  |                                                                                                                                                           |
|                    | `FieldType.number`             | `'number'`                   |                                                                                                                                                           |
|                    | `FieldType.dateIso`            | `'dateIso'`                  |                                                                                                                                                           |
| ...                | ...                            | ...                          |                                                                                                                                                           |
| `FileType`         | `FileType.csv`                 | `'csv'`                      |                                                                                                                                                           |
|                    | `FileType.xlsx`                | `'xlsx'`                     |                                                                                                                                                           |
| ...                | ...                            | ...                          |                                                                                                                                                           |
| `GridStateType`    | `GridStateType.columns`        | `'columns'`                  |                                                                                                                                                           |
|                    | `GridStateType.filters`        | `'filters'`                  |                                                                                                                                                           |
|                    | `GridStateType.sorters`        | `'sorters'`                  |                                                                                                                                                           |
| ...                | ...                            | ...                          |                                                                                                                                                           |
| `OperatorType`     | `OperatorType.greaterThan`     | `'>'` or `'GT'`              | See [Operator](https://github.com/ghiscoding/slickgrid-universal/blob/master/packages/common/src/enums/operator.type.ts) list for all available operators |
|                    | `OperatorType.lessThanOrEqual` | `'<='` or `'LE'`             |                                                                                                                                                           |
|                    | `OperatorType.contains`        | `'Contains'` or `'CONTAINS'` | Operators are written as PascalCase                                                                                                                       |
|                    | `OperatorType.equal`           | `'='` or `'EQ'`              |                                                                                                                                                           |
|                    | `OperatorType.rangeExclusive`  | `'RangeExclusive'`           |                                                                                                                                                           |
| ...                | ...                            | ...                          |                                                                                                                                                           |
| `SortDirection`    | `SortDirection.ASC`            | `'ASC'` or `'asc'`           |                                                                                                                                                           |
|                    | `SortDirection.DESC`           | `'DESC'` or `'desc'`         |                                                                                                                                                           |
| ...                | ...                            | ...                          |                                                                                                                                                           |

**renaming `editorOptions` and `filterOptions` to a more generic `options` property**

```diff
import { type MultipleSelectOption } from '@slickgrid-universal/common';

columnDefinitions = [{
  id: 'duration', field: 'duration', name: 'Duration',
  editor: {
-   editorOptions: {
+   options: {
      maxHeight: 250, useSelectOptionLabelToHtml: true,
    } as MultipleSelectOption,
  },
  filter: {
-   filterOptions: {
+   options: {
      maxHeight: 250, useSelectOptionLabelToHtml: true,
    } as MultipleSelectOption,
  }
}];

// or reuse the same `options`
+ const msOptions = { maxHeight: 250, useSelectOptionLabelToHtml: true } as MultipleSelectOption;

columnDefinitions = [{
  id: 'duration', field: 'duration', name: 'Duration',
  editor: {
+   options: msOptions,
  },
  filter: {
+   options: msOptions,
  },
}];
```

**renaming all `text-color-xyz` to `color-xyz`**

I decided to remove all `text-color-...` and rename them all to `color-...` which is much shorter and easier to use.

You can do a "Search and Replace" in VSCode via Regular Expressions to replace them all easily:

| Search        | Replace  |
| ------------- | -------- |
| `text-color-` | `color-` |

For example:

```diff
- <span class="text-color-primary">Primary Text</span>
+ <span class="color-primary">Primary Text</span>
```

**renaming all `mdi-[0-9]px` to `font-[0-9]px`**

Since I had 2 CSS utilities that do exactly the same, I dropped all `mdi-..px` in favor of `font-..px` because it makes more sense to represent font sizes that also work on any type of elements (not just icons).

You can do a "Search and Replace" in VSCode via Regular Expressions to replace them all easily (**make sure to use `regex` in VSCode Search & Replace**):

| Search (regex)   | Replace     |
| ---------------- | ----------- |
| `mdi-([0-9]*)px` | `font-$1px` |

For example:

```diff
- <span class="mdi mdi-check mdi-22px"></span> Checkmark Icon
+ <span class="mdi mdi-check font-22px"></span> Checkmark Icon
```

***

### What's next? ...version 11?

Wait, are you seriously talking about version 11 when version 10 actually just shipped? That's right, I'm already thinking ahead and planning the next major version, which will be in about a year from now (2027 Q1). I can already say that the main focus will be around the use of native [CSS anchor positioning](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_anchor_positioning) to replace JS code for positioning menus, tooltips, etc... which will help decreasing the build size further by using more native code. CSS anchoring has been around for a while in Chrome, but its addition in Firefox(147) is quite recent, so for that reason I'm postponing its usage for next year. There's also the new [Sanitizer API](https://developer.mozilla.org/en-US/docs/Web/API/Sanitizer) (to replace DOMPurify) that I'm hoping to see more availability by next year (Safari is lagging).

#### Code being `@deprecated` (to be removed in the future, 2027-Q1)

**You can already start using these new options and props (shown below) in v10.0 and above.**

Deprecating `ExtensionName` enum which will be replaced by its string literal type (which I forgot to deprecate in v9.x, better late than never), for example:

**Hint** You can use VSCode search & replace, but make sure it's set to Regular Expression search pattern

| Search (regex)                 | Replace  |
| ------------------------------ | -------- |
| `ExtensionName\.([a-z_]+)(.*)` | `'$1'$2` |

Below is an abbreviated list of Enums to update, make sure to update them all

| Enum Name       | from `enum`                 | to string `type` |
| --------------- | --------------------------- | ---------------- |
| `ExtensionName` | `ExtensionName.autoTooltip` | `'autoTooltip'`  |
|                 | `ExtensionName.gridMenu`    | `'gridMenu'`     |
|                 | `ExtensionName.rowDetail`   | `'rowDetail'`    |
| ...             | ...                         | ...              |

Also as mentioned above in the section [Menu with Commands](#menu-with-commands-slot-renderer), all menu `positionOrder` and `hide...` flags are being deprecated in favor of the new `hideCommands: [...]` or the `commandListBuilder`, for example:

```diff
gridOptions = {
  gridMenu: {
    // @deprecated properties
-   hideExportCsvCommand: true,
-   hideTogglePreHeaderCommand: true,

    // hide via command name(s)
+   hideCommands: ['export-csv', 'toggle-preheader'],

    // or hide via builder
+   commandListBuilder: (cmdItems) => cmdItems.filter(x => x !== 'divider' && x.command !== 'export-csv' && x.command !== 'toggle-preheader')
  }
}
```

**Menu Options `optionItems` (deprecated)**

Menu Options list, using `optionItems` are now deprecated and will be removed in next major v11. That is quite similar to Command List and barely anyone uses it, so let's remove it in v11 and just use `commandItems` instead (see [docs](https://ghiscoding.gitbook.io/slickgrid-universal/column-functionalities/cell-menu#default-usage) for both usages).

***

If the project is useful to you, please give it a star ⭐ (on the [Slickgrid-Universal](https://github.com/ghiscoding/slickgrid-universal) umbrella project). I do also like to drink coffee [☕ (Ko-Fi)](https://ko-fi.com/ghiscoding). Happy Coding 🧑‍💻
