Skip to content

Migrating to v6 ​

Version 6 is a major release. It removes the last runtime dependency, replaces frozen panes with pinning and sticky docking, keeps hidden columns in the column array, and drops the CommonJS build. This page is the complete list of breaking changes between 5.20.2 and 6.0.0, with what to change for each one.

Work through the sections that match what your application uses. Most applications only need Installing v6, Frozen panes become pinning, Columns: the hidden property and Styling and themes. The later sections matter if you subclass grid classes, write custom plugins, or test the grid's DOM.

AI agents can use the SlickGrid v6 migration skill alongside this guide.

Installing v6 ​

ESM only (PRs #1310, #1343) ​

The CommonJS build is gone. dist/cjs is no longer published, and the package main now points at ./dist/esm/index.mjs.

  • Use import { SlickGrid } from 'slickgrid'. require('slickgrid') only works where Node supports require() of ES modules.
  • The IIFE build in dist/browser (the global Slick namespace) is unchanged.

Node.js version (PR #1344) ​

engines.node is now ^20.19.0 || >=22.12.0 (it was >=18.0.0).

dist/ is no longer committed (PR #1312) ​

The built files are published to npm only.

  • Load the files from npm or an npm CDN, for example https://cdn.jsdelivr.net/npm/slickgrid@6/dist/browser/slick.grid.js or unpkg.
  • GitHub raw URLs, cdn.jsdelivr.net/gh/... URLs, git dependencies and submodules no longer contain dist/.
  • If you build SlickGrid yourself, the build script is now npm run build (it was npm run build:prod).

SortableJS is gone (PRs #1242–#1244) ​

The grid now uses native browser drag and drop, and the package has no runtime dependencies.

  • Remove any <script> tag that loads Sortable, and any global assignment such as window.Sortable = Sortable.
  • If your application uses sortablejs itself, add it as a direct dependency.
  • Column reordering (enableColumnReorder) and draggable grouping keep working without new configuration. The Draggable Grouping API changes are listed under Plugins and controls.

Removed exports ​

RemovedReplacement
FieldType constant (PR #1314)The string values, such as 'number' and 'date'. import { FieldType } from 'slickgrid' now fails at runtime.
OnBeforeAppendCellEventArgs type (PR #1320)None; see onBeforeAppendCell.
FilterCspFn and FilterWithCspCachingFn types (PR #1325)FilterFn<T>.

Frozen panes become pinning and sticky docking ​

PR #1302. Version 6 removes frozen panes. The grid has one scrollable viewport, and the pinning option docks columns and rows at its edges. You can now pin columns on the right as well as the left, pin rows at the top and bottom at the same time, and make columns and rows sticky, so that they dock at an edge only while scrolling would hide them.

diff
const gridOptions = {
- frozenColumn: 1,
- frozenRow: 2,
+ pinning: {
+   columns: { left: 1 },
+   rows: { top: [0, 1] },
+ },
};

Options ​

v5v6
frozenColumn: Npinning: { columns: { left: N } }. The boundary is the same, but it now counts visible columns only.
frozenRow: Npinning: { rows: { top: [0, …, N-1] } }
frozenRow: N, frozenBottom: truepinning: { rows: { bottom: [len-N, …, len-1] } }
frozenRightViewportMinWidthRemoved. Use docking.maxColumnViewportWidthPercent.
skipFreezeColumnValidationskipPinningValidation
invalidColumnFreezePickerMessage, invalidColumnFreezeWidthMessageinvalidColumnPinningPickerMessage, invalidColumnPinningWidthMessage
invalidColumnFreezePickerCallback, invalidColumnFreezeWidthCallbackThe shared errorCallback (PR #1318)
throwWhenFrozenNotAllViewableRemoved, with no throwing variant.

All error messages now go through the single errorCallback. The individual messages stay configurable through invalidColumnPinningPickerMessage, invalidColumnPinningWidthMessage and invalidColumnPinningSequenceMessage:

diff
const gridOptions = {
- invalidColumnFreezePickerCallback: (msg) => alert(msg),
- invalidColumnFreezeWidthCallback: (msg) => alert(msg),
+ errorCallback: (msg) => alert(msg),
};

Methods ​

v5v6
getFrozenColumnId()getPinnedColumns()
validateColumnFreezeWidth(), validateSetColumnFreeze()validateColumnPinning()
getFrozenRowOffset(), calculateFrozenColumnIndexById()Removed; row offsets are internal.
setColumns(columns)Now returns a boolean. It returns false, and changes nothing, when it rejects the pinning of the new columns. It also writes pinned onto the columns from options.pinning.

There is one viewport and one canvas, so the pane getters return one element:

  • getCanvasNode() and getViewportNode() ignore their arguments.
  • getHeader() with no argument returns one element, not an array.
  • getTopPanels() returns one panel. getPreHeaderPanelRight() returns the same element as getPreHeaderPanelLeft().
  • getCanvases(), getViewports(), getHeaderRow() and getFooterRow() return one entry where they returned left and right pairs.

Column reordering across the pinned boundary is not possible; pin or unpin the column explicitly. The Grid State plugin does not persist frozenColumn; store pinning from grid.getOptions() instead.

CSS classes and DOM ​

  • Removed: the .slick-pane and .slick-pane-* classes, .slick-viewport-right, .slick-viewport-bottom, .grid-canvas-right, .grid-canvas-bottom and .slick-header-right.
  • Removed: the frozen class on header, header-row and footer cells. Use .slick-column-pinned-left, .slick-cell-pinned-left and their -right and -edge variants.
  • slick-viewport-top slick-viewport-left and grid-canvas-top grid-canvas-left remain on the single viewport and canvas.
  • .slick-header-columns-right, .slick-headerrow-columns-right and .slick-footerrow-columns-right still exist, but only as the right-pinned band wrappers inside a .slick-docking-chrome row, not as a second pane.
  • New wrappers (.slick-header-root, .slick-content-root, .slick-header-container and .slick-preheader-container) break direct-child selectors such as .slick-pane-header > .slick-header.

See Pinning and sticky docking for the full feature guide.

Columns: the hidden property ​

PR #1299. Version 6 keeps all columns at all times. To hide a column, set hidden: true on it instead of removing it from the array. This makes show and hide reversible and keeps each column's settings while it is hidden.

  • Do not filter columns out of the array to hide them. Set hidden instead.
  • getColumns() returns every column, including hidden ones. Use getVisibleColumns() to read only the visible ones.
  • Use grid.updateColumnById('id', { hidden: true }) followed by grid.updateColumns() to toggle a column.
  • Column Picker and Column Menu onColumnsChanged: columns now holds the visible columns only (it held all of them), and allColumns is grid.getColumns(). Toggling calls updateColumnById() and updateColumns(), not setColumns(visible), and the last visible column can no longer be unchecked.
  • Row and Hybrid selection: full-row ranges end at the last visible column.
  • SlickState: the saved column state includes hidden. On restore, columns missing from the saved state are kept with hidden: true instead of being dropped.

Column objects are copied (mixinDefaults) ​

The mixinDefaults grid option now defaults to false (it was true). The grid applies the column defaults to copies of your column objects, not to the objects themselves.

Code that keeps a reference to a column object and mutates it no longer affects the grid:

diff
- columns[2].hidden = true;
- grid.updateColumns();
+ grid.updateColumnById(columns[2].id, { hidden: true });
+ grid.updateColumns();

Read the grid's own columns with getColumns() or getColumnById(), change them with updateColumnById(), or set mixinDefaults: true to keep the v5 behaviour.

Grid rendering and behaviour ​

rowTopOffsetRenderType is removed (PR #1319) ​

Remove the option from your configuration, whether its value was 'top' or 'transform'. Row Detail and RowSpan no longer need an explicit 'top' setting.

diff
const gridOptions = {
- rowTopOffsetRenderType: 'top',
  rowHeight: 25,
};

Ordinary rows are positioned with transform: translateY(25px) instead of top: 25px. RowSpan host rows and the rows they cover now carry the .slick-rowspan class and keep top positioning, so spanning cells and pinned columns stack correctly. Update tests and CSS that read a row's top.

Scroll rendering (PR #1320) ​

  • scrollRenderThrottling defaults to 0 (it was 10), so large vertical jumps render synchronously. Set a positive delay, such as 10, to keep timer throttling.
  • Horizontal scrolling now renders on the next animation frame, even with forceSyncScrolling. In 5.20.2 it rendered synchronously. It also re-renders only after scrolling about 80% of the viewport width (it was 20px), and onViewportChanged fires before the new cells are rendered.

onBeforeAppendCell is removed ​

The per-cell onBeforeAppendCell event and its OnBeforeAppendCellEventArgs type are removed. Return classes from a formatter instead:

ts
const formatter = (_row, _cell, value) => ({
  text: String(value),
  addClasses: value > 50 ? 'high-value' : '',
});

Plain-text formatter results skip the sanitizer ​

A formatter result that is a plain string, with no < or &, is now written with textContent and does not go through the sanitizer. Markup and strings with entities still use the sanitizer. Do not use a sanitizer as a general text transformation hook.

Context menu event ​

onContextMenu now also fires when you right-click the canvas outside a cell, with { row: -1, cell: -1 }. In 5.20.2 it fired over cells only, with empty args; it now passes { row, cell }. Check for -1 if your handler assumes a cell.

Keyboard ​

Grid keyboard handling reads e.key instead of e.which or keyCode. Synthetic keyboard events in tests must set key. F2 now opens the editor of the active cell.

Events: unsubscribe() with no handler ​

PR #1345.

  • SlickEvent.unsubscribe() with no argument now removes every handler. It used to remove nothing. As a result, destroy() of GridMenu, CellMenu, ContextMenu, Resizer, RowDetailView, DraggableGrouping and DataView now really drops the subscriptions to their own events. Subscribe again if you reuse an instance.
  • Do not call grid.onXxx.unsubscribe() without a handler unless you mean to remove everyone's handlers. Use a SlickEventHandler to remove only your own.
  • notify() runs over a copy of the handler list. A handler unsubscribed during a notify is skipped, and one subscribed during a notify runs from the next notify.

Copy and paste: the async Clipboard API ​

PR #1270. SlickCellExternalCopyManager now uses the browser's asynchronous Clipboard API (navigator.clipboard) instead of a hidden textarea.

  • The Clipboard API needs a secure context (HTTPS or localhost). Paste also needs clipboard-read permission, and it now completes asynchronously.
  • Removed options: bodyElement and clipboardPasteDelay.
  • New options: clipboardWriteOverride and clipboardReadOverride. Use them where the Clipboard API is unavailable or the host application manages the clipboard.
  • Keys are detected with e.key, and the IE window.clipboardData path is gone.
  • Copy calls preventDefault(). Clipboard errors are logged instead of thrown.
  • The onPasteCells range ends at the last column actually pasted, and CRLF counts as one row delimiter.
  • Subclasses: _createTextBox(), _bodyElement and keyCodes are removed. _decodeTabularData(grid, clipText) now takes the clipboard text instead of a textarea, and handleKeyDown() is async.

See the CellExternalCopyManager reference for details.

Column autosizing ​

PR #1328.

  • Content autosizing samples the first 200 rows by default, in every column mode (autoSize.rowSelectionCount was 100).
  • ContentIntelligent number and string columns used to read every row. They now read the rows chosen by the column's own rowSelectionMode and rowSelectionCount, so the first 200 by default. Set autoSize.rowSelectionMode: RowSelectionMode.AllRows on a column to read every row again.
  • TypeScript: the autosize settings are typed as unions of their constants instead of string. This covers autosizeColsMode, the autosizeColumns() argument, and autoSize.autosizeMode, rowSelectionMode, rowSelectionModeOnInit, valueFilterMode and widthEvalMode. Misspelt values become compile errors. Code that uses the constants (GridAutosizeColsMode.FitColsToViewport, ColAutosizeMode.Locked, ...) or their literal values needs no change. A value held in a string variable, for example one read from configuration, needs a type assertion such as value as ColAutosizeModeValue. The new *Value types are exported for this.
  • autoSize.rowSelectionModeOnInit was typed boolean but holds a RowSelectionMode value; it is now typed as one.
  • GridAutosizeColsMode, ColAutosizeMode, RowSelectionMode, ValueFilterMode and WidthEvalMode are declared as const.

Removed deprecated code ​

Replace these before upgrading.

DataView filtering ​

PR #1325. DataView filtering and aggregation are CSP-safe without runtime code generation. Remove inlineFilters and useCSPSafeFilter from DataView options; neither needs a replacement. The unused FilterCspFn and FilterWithCspCachingFn type aliases are also removed. Use FilterFn<T> for the predicate passed to setFilter().

Subclasses of SlickDataView must update references to these protected methods:

Previous methodReplacement
compileFilterCSPSafe()filterItems()
compileFilterWithCachingCSPSafe()filterItemsWithCaching()
compileAccumulatorLoopCSPSafe()compileAccumulatorLoop()

DataView fastSort() ​

The IE-specific fastSort(field, ascending) method and the protected fastSortField are removed. Use sort(comparer, ascending) instead:

ts
dataView.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0), true);

reSort() continues to reapply the comparer and direction passed to sort().

  • Grid Menu: use commandItems and commandTitle in place of customItems and customTitle, nested entries included. Remove resizeOnShowHeaderRow; flexbox handles header sizing.
  • Header Menu: use header.menu.commandItems in place of items, nested entries included.
  • Header Menu itemVisibilityOverride and itemUsabilityOverride callbacks receive the command list directly in args.menu, as HeaderMenuCommandItemCallbackArgs declares. Change args.menu.items to args.menu.
  • The top-level grid options columnPickerTitle, forceFitTitle and syncResizeTitle are removed. Set columnTitle, forceFitTitle and syncResizeTitle under columnPicker.
  • Column Menu and Column Picker: rename setColumnVisibiliy() to setColumnVisibility().

Other removals ​

  • Column excludeFromQuery is removed (PR #1314).
  • The Resizer plugin's resizeGrid() always returns a Promise; the fallback for browsers without Promise support is gone.
  • MouseWheel interactions no longer fall back to window.event.
  • IE-specific stylesheet and global-event fallbacks are removed.

Plugins and controls ​

Draggable Grouping ​

  • getSetupColumnReorder() returns { columnReorderDragInstance }, an object with a destroy() method. In 5.20.2 it returned the SortableJS instances { sortableLeftInstance, sortableRightInstance }.
  • The protected _droppableInstance, _sortableLeftInstance, _sortableRightInstance, destroySortableInstances() and addDragOverDropzoneListeners() are removed.
  • The drag ghost is .slick-header-column-drag-ghost; .slick-sortable-placeholder is no longer applied.

Row Detail View ​

PR #1319. The plugin renders one .slick-row-detail-container.row-detail-{id} panel directly in the grid canvas. Each panel sits over the padding rows reserved below its parent and stays within the visible viewport width while scrolling horizontally. The panel itself is the content mount point.

  • Removed containers and classes: .dynamic-cell-detail, .detail-container, .innerDetailView_{id}, .detailViewContainer_{id} and .cellDetailView_{id}.
  • The panel carries the plugin's line-height: 13px, which the removed content wrapper used to set, so every top-level element of a template inherits it. Override it on .slick-row-detail-container.
  • Panels are recreated as rows leave and re-enter the rendered range.
  • The formatter no longer returns insertElementAfterTarget, and the handleScroll() signature changed.
diff
- .dynamic-cell-detail .innerDetailView_{id}
+ .slick-row-detail-container.row-detail-{id}

Grid Menu ​

PR #1323.

  • The button is wrapped in a flexbox .slick-gridmenu-container, and the header is no longer sized with calc(100% - Npx). Review custom CSS that positions .slick-gridmenu-button or overrides header widths.
  • menuWidth defaults to 12 pixels, plus 2 pixels of spacing, and acts as a minimum: an icon class wider than that widens the slot instead of being clipped.
  • iconButtonContainer: 'preheader' needs a .slick-preheader-panel.

Custom Tooltip ​

PR #1316.

  • Tooltips no longer have an arrow. The hideArrow option and the .tooltip-arrow, .arrow-up, .arrow-down and .arrow-{left,center,right}-align classes are removed.
  • The content now goes into a child .tooltip-body element (see bodyClassName).
  • A custom className is appended to slick-custom-tooltip instead of replacing it.
  • A missing asyncPostFormatter or a rejected asyncProcess is logged instead of thrown.

The plugin can now also show tooltips on elements outside the grid; see Custom tooltips.

Header Menu, Cell Menu and Context Menu ​

PR #1347.

  • Header Menu constructor options now override the defaults. Before, minWidth, autoAlign, autoAlignOffset and subMenuOpenByEvent passed to the constructor were silently ignored.
  • Cell Menu and Context Menu: returning false from onAfterMenuShow now closes the menu, as documented.

Editors ​

PR #1347.

  • With editorCellNavOnLRKeys, Left and Right move to the next cell only when the cursor is at the start or end of the text. Before, the grid always navigated, and Right fired one character early.
  • isValueChanged() compares values as strings, so untouched number, date and yes/no fields no longer count as changed. TextEditor loads 0 as '0'.
  • LongTextEditor's protected selectionStart field is removed.

Accessibility ​

PR #1338. Most applications need no configuration changes, but custom accessibility integrations and DOM tests may need updates.

  • aria-rowindex and aria-rowcount count the visible column-header and header-filter rows, and the add-new row when available. Data row indexes no longer start at 1.
  • The container has aria-colcount (all columns, hidden ones included), and header and data cells have aria-colindex.
  • Selected cells have aria-selected, and the primary sorted column has aria-sort.
  • Built-in editors use the rendered column title as their accessible name, falling back to the column ID. Set editorAriaLabel on a column for a different or translated name.
  • Checkbox Select Column: labels come from the rowAriaLabel and selectAllAriaLabel options; rowAriaLabel names every row checkbox alike, in place of the default Select row N. aria-checked is no longer rendered, and createCheckboxElement() gained an ariaLabel parameter.
  • Header Buttons: the default aria-label is ariaLabel || tooltip || command (it was always "Header Button"). Buttons are focusable, respond to Enter and Space, and no longer call action when disabled.
  • Header menu buttons are focusable, with aria-haspopup and aria-expanded, arrow, Home, End and Escape keys in the menu, and focus returned on close. Menu and header buttons show on keyboard focus.
  • Pager icons and row-detail toggles are focusable and respond to keys. Menu dividers have role="separator" and disabled items aria-disabled.
  • The PercentCompleteBar, Checkbox and Checkmark formatters include text alternatives. CheckmarkFormatter returns <span role="img" aria-label="No"></span> for false values instead of an empty string. Update tests that compare formatter HTML.
  • Custom tooltips keep an element's existing aria-describedby references while the tooltip is shown.

For example, column and plugin options can provide application-specific labels in an IIFE application:

ts
const columns = [{
  id: 'title',
  name: 'Title',
  field: 'title',
  editor: Slick.Editors.Text,
  editorAriaLabel: 'Edit task title',
}];

const checkboxSelector = new Slick.CheckboxSelectColumn({
  rowAriaLabel: 'Select task',
  selectAllAriaLabel: 'Select all tasks',
});
columns.unshift(checkboxSelector.getColumnDefinition()); // the plugin's own column holds the checkboxes

const grid = new Slick.Grid('#myGrid', data, columns, { editable: true, enableCellNavigation: true });
grid.setSelectionModel(new Slick.RowSelectionModel({ selectActiveRow: false }));
grid.registerPlugin(checkboxSelector);

For ESM, import SlickGrid, TextEditor, SlickRowSelectionModel and SlickCheckboxSelectColumn from slickgrid and use those names in place of Slick.Grid, Slick.Editors.Text, Slick.RowSelectionModel and Slick.CheckboxSelectColumn.

Styling and themes ​

Alpine theme variables (PR #1317) ​

All $alpine-* SASS variables are renamed to $slick-*, and all --alpine-* CSS custom properties to --slick-*, with the same suffixes and values:

diff
// SASS
- $alpine-odd-row-color: #fbfbfb;
+ $slick-odd-row-color: #fbfbfb;

/* CSS */
body {
- --alpine-odd-row-color: #fbfbfb;
+ --slick-odd-row-color: #fbfbfb;
}

jQuery UI class leftovers (PR #1313) ​

The remaining .ui-* classes are removed from the grid, controls and plugins. Rename them in your CSS and selectors:

v5v6
.ui-state-default, .ui-state-hover, .ui-state-active.slick-state-default, .slick-state-hover, .slick-state-active
.ui-widget (grid container).slick-widget
.ui-widget-content (rows).slick-widget-content
.ui-icon-container (pager).slick-icon-container

Resize handles and headers ​

  • The default theme's column resize handle is 6px wide (it was 9px), sits at right: 0 (it was -5px) and has z-index: 4.
  • The Alpine handle is 6px wide, with its separator line moved to ::before. Both themes add an ::after hover pill.
  • Alpine and the default theme style headers through .slick-header-column.slick-state-default, so plain .slick-header-column { … } overrides can lose on specificity. The default theme also sets the header height, padding and background.

New SASS partial ​

The themes @use the new _slick-docking.scss. Copy it too if you copy individual .scss files into your project.

Subclasses: protected members ​

If you subclass SlickGrid or a plugin, these protected members changed:

  • trigger() became the public triggerEvent(), with no alias (PR #1315).
  • The frozen-pane helpers are removed: getFrozenColumnIdx, hasFrozenColumns, setFrozenOptions, setPaneVisibility, setPaneFrozenClasses, isFrozenRowIdx, isBottomBandRow, computeFrozenRowsHeight and _getContainerElement.
  • Also removed: clearTextSelection, dirSide and LogColWidths. destroyAllElements is renamed destroyElementReferences.
  • Cell Range Selector: _rowOffset, _columnOffset, _isRightCanvas and _isBottomCanvas are removed.
  • The DataView, Clipboard, Draggable Grouping and LongTextEditor changes are listed in their own sections above.

New in v6 ​

These additions are not breaking, but most of them replace something above.

  • Pinning and sticky docking: the pinning, stickyRows, docking, skipPinningValidation, errorCallback, invalidColumnPinningPickerMessage, invalidColumnPinningSequenceMessage, invalidColumnPinningWidthMessage, allowDragFromClosest and columnResizingDelay options; the pinned and sticky column properties; the getPinnedColumns(), setColumnPinning(), setColumnStickiness() and validateColumnPinning() methods; and the onHeaderMouseOver, onHeaderMouseOut, onHeaderRowMouseOver, onHeaderRowMouseOut and onHeaderKeyDown events.
  • Hidden columns: the spreadHiddenColspan option and the getColumnById(), getVisibleColumnIndex(), updateColumnById() and getRowTop() methods.
  • Custom tooltips: bodyClassName, repositionByMouseOverTarget, useRegularTooltipFromCellTextOnly, persistOnHover, autoHideDelay, observeAllTooltips and observeTooltipContainer.
  • Accessibility: the editorAriaLabel column property, the Checkbox Select Column rowAriaLabel and selectAllAriaLabel options, and the header button ariaLabel.

All of them are in the Reference.

See also ​