diff --git a/packages/crud/test/dom/__snapshots__/crud.test.snap.js b/packages/crud/test/dom/__snapshots__/crud.test.snap.js
index 7482110a352..8828ceb384a 100644
--- a/packages/crud/test/dom/__snapshots__/crud.test.snap.js
+++ b/packages/crud/test/dom/__snapshots__/crud.test.snap.js
@@ -106,7 +106,7 @@ snapshots["vaadin-crud host default"] =
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
John
-
+
30
-
+
` element for a cell.
+ */
+class CellContentDirective extends AsyncDirective {
+ #cell;
+
+ update(part, [grid, slotName]) {
+ this.#cell = part.parentNode;
+ this.#cell._content ??= document.createElement('vaadin-grid-cell-content');
+ this.#cell._content.slot = slotName;
+
+ if (!grid.contains(this.#cell._content)) {
+ grid.appendChild(this.#cell._content);
+ }
+
+ return html` `;
+ }
+
+ disconnected() {
+ this.#cell._content?.remove();
+ }
+}
+
+export const cellContent = directive(CellContentDirective);
diff --git a/packages/grid/src/vaadin-grid-column-auto-width-mixin.js b/packages/grid/src/vaadin-grid-column-auto-width-mixin.js
index ccc9b902f66..4fe473672e8 100644
--- a/packages/grid/src/vaadin-grid-column-auto-width-mixin.js
+++ b/packages/grid/src/vaadin-grid-column-auto-width-mixin.js
@@ -137,11 +137,7 @@ export const ColumnAutoWidthMixin = (superClass) =>
_recalculateColumnWidths() {
// Flush to make sure DOM is up-to-date when measuring the column widths
this.__virtualizer.flush();
- [...this.$.header.children, ...this.$.footer.children].forEach((row) => {
- if (row.__debounceUpdateHeaderFooterRowVisibility) {
- row.__debounceUpdateHeaderFooterRowVisibility.flush();
- }
- });
+ this.__renderHeaderFooterDebouncer?.flush();
this.__hasHadRenderedRowsForColumnWidthCalculation ||= this._getRenderedRows().length > 0;
diff --git a/packages/grid/src/vaadin-grid-column-mixin.js b/packages/grid/src/vaadin-grid-column-mixin.js
index 8e8dae3c7b7..4cc0a0740a3 100644
--- a/packages/grid/src/vaadin-grid-column-mixin.js
+++ b/packages/grid/src/vaadin-grid-column-mixin.js
@@ -7,7 +7,8 @@ import { animationFrame } from '@vaadin/component-base/src/async.js';
import { Debouncer } from '@vaadin/component-base/src/debounce.js';
import { DirMixin } from '@vaadin/component-base/src/dir-mixin.js';
import { get } from '@vaadin/component-base/src/path-utils.js';
-import { updateCellState, updatePart } from './vaadin-grid-helpers.js';
+import { generateUniqueId } from '@vaadin/component-base/src/unique-id-utils.js';
+import { updateCellState } from './vaadin-grid-helpers.js';
export const ColumnBaseMixin = (superClass) =>
class ColumnBaseMixin extends superClass {
@@ -270,7 +271,7 @@ export const ColumnBaseMixin = (superClass) =>
'_onRendererOrBindingChanged(_renderer, _cells, _bodyContentHidden, path)',
'_onHeaderRendererOrBindingChanged(_headerRenderer, _headerCell, path, header)',
'_onFooterRendererOrBindingChanged(_footerRenderer, _footerCell)',
- '_resizableChanged(resizable, _headerCell)',
+ '_resizableChanged(resizable)',
'_reorderStatusChanged(_reorderStatus, _headerCell, _footerCell, _cells)',
'_hiddenChanged(hidden, _headerCell, _footerCell, _cells)',
'_rowHeaderChanged(rowHeader, _cells)',
@@ -302,6 +303,19 @@ export const ColumnBaseMixin = (superClass) =>
.filter((cell) => cell);
}
+ constructor() {
+ super();
+
+ /**
+ * A stable unique id assigned once per column instance. Used to build
+ * cell content slot names that stay stable across re-renders, so lit
+ * can reuse the cell content elements when the column tree changes.
+ *
+ * @protected
+ */
+ this._id = generateUniqueId();
+ }
+
/** @protected */
connectedCallback() {
super.connectedCallback();
@@ -313,7 +327,7 @@ export const ColumnBaseMixin = (superClass) =>
return;
}
- this._allCells.forEach((cell) => {
+ this._cells?.forEach((cell) => {
if (!cell._content.parentNode) {
this._grid.appendChild(cell._content);
}
@@ -332,7 +346,7 @@ export const ColumnBaseMixin = (superClass) =>
return;
}
- this._allCells.forEach((cell) => {
+ this._cells?.forEach((cell) => {
if (cell._content.parentNode) {
cell._content.parentNode.removeChild(cell._content);
}
@@ -485,27 +499,12 @@ export const ColumnBaseMixin = (superClass) =>
}
/** @private */
- _resizableChanged(resizable, headerCell) {
- if (resizable === undefined || headerCell === undefined) {
+ _resizableChanged(resizable) {
+ if (resizable === undefined || this._grid === undefined) {
return;
}
- if (headerCell) {
- [headerCell].concat(this._emptyCells).forEach((cell) => {
- if (cell) {
- const existingHandle = cell.querySelector('[part~="resize-handle"]');
- if (existingHandle) {
- cell.removeChild(existingHandle);
- }
-
- if (resizable) {
- const handle = document.createElement('div');
- updatePart(handle, 'resize-handle', true);
- cell.appendChild(handle);
- }
- }
- });
- }
+ this._grid.__scheduleRenderHeaderFooter?.();
}
/** @private */
@@ -531,7 +530,7 @@ export const ColumnBaseMixin = (superClass) =>
if (!!hidden !== !!this._previousHidden && this._grid) {
if (hidden === true) {
- this._allCells.forEach((cell) => {
+ this._cells?.forEach((cell) => {
if (cell._content.parentNode) {
cell._content.parentNode.removeChild(cell._content);
}
@@ -632,9 +631,8 @@ export const ColumnBaseMixin = (superClass) =>
}
this.__renderCellsContent(headerRenderer, [headerCell]);
- if (this._grid && headerCell.parentElement) {
- this._grid.__debounceUpdateHeaderFooterRowVisibility(headerCell.parentElement);
- }
+
+ this._grid?.__scheduleRenderHeaderFooter();
}
/** @protected */
@@ -689,9 +687,8 @@ export const ColumnBaseMixin = (superClass) =>
}
this.__renderCellsContent(footerRenderer, [footerCell]);
- if (this._grid && footerCell.parentElement) {
- this._grid.__debounceUpdateHeaderFooterRowVisibility(footerCell.parentElement);
- }
+
+ this._grid?.__scheduleRenderHeaderFooter();
}
/** @protected */
diff --git a/packages/grid/src/vaadin-grid-column-rendering-mixin.js b/packages/grid/src/vaadin-grid-column-rendering-mixin.js
new file mode 100644
index 00000000000..ef23d29f9f7
--- /dev/null
+++ b/packages/grid/src/vaadin-grid-column-rendering-mixin.js
@@ -0,0 +1,195 @@
+/**
+ * @license
+ * Copyright (c) 2016 - 2026 Vaadin Ltd.
+ * This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
+ */
+import { html, nothing, render } from 'lit';
+import { cache } from 'lit/directives/cache.js';
+import { repeat } from 'lit/directives/repeat.js';
+import { microTask } from '@vaadin/component-base/src/async.js';
+import { Debouncer } from '@vaadin/component-base/src/debounce.js';
+import { cellContent } from './directives/cell-content-directive.js';
+
+function isEmptyCell(column, level, columnTree) {
+ const isColumnRow = level === columnTree.length - 1;
+ return !isColumnRow && column.localName !== 'vaadin-grid-column-group';
+}
+
+function isHeaderRowVisible(columns, level, columnTree) {
+ return columns.some((column) => {
+ if (column.hidden || isEmptyCell(column, level, columnTree)) {
+ return false;
+ }
+
+ if (column.headerRenderer) {
+ // The column has a header renderer -> row should be visible
+ return true;
+ }
+
+ if (column.header === null) {
+ // The column header is explicitly set to null -> doesn't block hiding the row
+ return false;
+ }
+
+ return column.path || column.header !== undefined;
+ });
+}
+
+function isFooterRowVisible(columns, level, columnTree) {
+ return columns.some((column) => {
+ if (column.hidden || isEmptyCell(column, level, columnTree)) {
+ return false;
+ }
+
+ return column.footerRenderer;
+ });
+}
+
+/**
+ * A mixin providing rendering of rows based on the column tree.
+ */
+export const ColumnRenderingMixin = (superClass) =>
+ class ColumnRenderingMixin extends superClass {
+ /** @private */
+ __scheduleRenderHeaderFooter() {
+ this.__renderHeaderFooterDebouncer = Debouncer.debounce(this.__renderHeaderFooterDebouncer, microTask, () => {
+ this.__renderHeaderFooter();
+ });
+ }
+
+ /** @private */
+ __renderHeaderFooter() {
+ this.__renderHeaderFooterDebouncer?.cancel();
+
+ const sortedColumnTree = (this._columnTree ?? []).map((columns) => {
+ return columns.toSorted((a, b) => a._order - b._order);
+ });
+
+ sortedColumnTree.flat().forEach((column) => {
+ column._emptyCells = [];
+ });
+
+ this.#renderHeader(sortedColumnTree);
+ this.#renderFooter(sortedColumnTree);
+
+ this._resetKeyboardNavigation();
+ this.__a11yUpdateGridSize(this.size, this._columnTree, this.__emptyState);
+ }
+
+ #renderHeader(columnTree) {
+ render(columnTree.map(this.#renderHeaderRow), this.$.header, { host: this });
+
+ this.$.table.toggleAttribute('has-header', !!this.$.header.querySelector('tr:not([hidden])'));
+ this.__updateHeaderFooterRowParts('header');
+
+ this.$.header.querySelectorAll('.header-cell').forEach((cell) => {
+ const column = cell._column;
+ const isColumnRow = cell.parentElement === this.$.header.lastElementChild;
+ if (isColumnRow || column.localName === 'vaadin-grid-column-group') {
+ column._headerCell = cell;
+ } else {
+ column._emptyCells.push(cell);
+ }
+ });
+ }
+
+ #renderHeaderRow = (columns, level, columnTree) => {
+ return html`
+
+ `;
+ };
+
+ #renderFooter(columnTree) {
+ render(columnTree.map(this.#renderFooterRow).toReversed(), this.$.footer, { host: this });
+
+ this.$.table.toggleAttribute('has-footer', !!this.$.footer.querySelector('tr:not([hidden])'));
+ this.__updateHeaderFooterRowParts('footer');
+
+ this.$.footer.querySelectorAll('.footer-cell').forEach((cell) => {
+ const column = cell._column;
+ const isColumnRow = cell.parentElement === this.$.footer.firstElementChild;
+ if (isColumnRow || column.localName === 'vaadin-grid-column-group') {
+ column._footerCell = cell;
+ } else {
+ column._emptyCells.push(cell);
+ }
+ });
+ }
+
+ #renderFooterRow = (columns, level, columnTree) => {
+ return html`
+
+ `;
+ };
+ };
diff --git a/packages/grid/src/vaadin-grid-column-reordering-mixin.js b/packages/grid/src/vaadin-grid-column-reordering-mixin.js
index fe04625a44b..43d7082762d 100644
--- a/packages/grid/src/vaadin-grid-column-reordering-mixin.js
+++ b/packages/grid/src/vaadin-grid-column-reordering-mixin.js
@@ -203,6 +203,8 @@ export const ColumnReorderingMixin = (superClass) =>
for (let i = startIndex; i !== endIndex; i += direction) {
this._swapColumnOrders(this._draggedColumn, levelColumnsInOrder[i + direction]);
}
+
+ this.__renderHeaderFooter();
}
this._updateGhostPosition(e.detail.x, this._touchDevice ? e.detail.y - 50 : e.detail.y);
@@ -434,7 +436,7 @@ export const ColumnReorderingMixin = (superClass) =>
}
/**
- * Swaps column orders and physically reorders cells in all rows.
+ * Swaps column orders and reorders cells in all rows.
* @param {!GridColumn} column1
* @param {!GridColumn} column2
* @protected
@@ -444,8 +446,7 @@ export const ColumnReorderingMixin = (superClass) =>
[column1._order, column2._order] = [column2._order, column1._order];
const [firstColumn, secondColumn] = column1._order < column2._order ? [column1, column2] : [column2, column1];
- // Reorder cells in all rows (header, footer, body, sizer)
- [...this.$.header.children, ...this.$.footer.children, ...this.$.items.children, this.$.sizer].forEach((row) => {
+ [...this.$.items.children, this.$.sizer].forEach((row) => {
const cells = getBodyRowCells(row);
const firstColumnCells = cells.filter((cell) => firstColumn.contains(cell._column));
const secondColumnFirstCell = cells.find((cell) => secondColumn.contains(cell._column));
@@ -456,6 +457,7 @@ export const ColumnReorderingMixin = (superClass) =>
}
});
+ this.__scheduleRenderHeaderFooter();
this._debounceUpdateFrozenColumn();
this._updateFirstAndLastColumn();
}
diff --git a/packages/grid/src/vaadin-grid-mixin.js b/packages/grid/src/vaadin-grid-mixin.js
index 96b56be0a60..ce65503cbc7 100644
--- a/packages/grid/src/vaadin-grid-mixin.js
+++ b/packages/grid/src/vaadin-grid-mixin.js
@@ -4,9 +4,7 @@
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { TabindexMixin } from '@vaadin/a11y-base/src/tabindex-mixin.js';
-import { microTask } from '@vaadin/component-base/src/async.js';
import { isAndroid, isIOS, isSafari, isTouch } from '@vaadin/component-base/src/browser-utils.js';
-import { Debouncer } from '@vaadin/component-base/src/debounce.js';
import { setTouchAction } from '@vaadin/component-base/src/gestures.js';
import { SlotObserver } from '@vaadin/component-base/src/slot-observer.js';
import { TooltipController } from '@vaadin/component-base/src/tooltip-controller.js';
@@ -15,6 +13,7 @@ import { A11yMixin } from './vaadin-grid-a11y-mixin.js';
import { ActiveItemMixin } from './vaadin-grid-active-item-mixin.js';
import { ArrayDataProviderMixin } from './vaadin-grid-array-data-provider-mixin.js';
import { ColumnAutoWidthMixin } from './vaadin-grid-column-auto-width-mixin.js';
+import { ColumnRenderingMixin } from './vaadin-grid-column-rendering-mixin.js';
import { ColumnReorderingMixin } from './vaadin-grid-column-reordering-mixin.js';
import { ColumnResizingMixin } from './vaadin-grid-column-resizing-mixin.js';
import { DataProviderMixin } from './vaadin-grid-data-provider-mixin.js';
@@ -48,17 +47,21 @@ export const GridMixin = (superClass) =>
ArrayDataProviderMixin(
DataProviderMixin(
DynamicColumnsMixin(
- ActiveItemMixin(
- ScrollMixin(
- SelectionMixin(
- SortMixin(
- RowDetailsMixin(
- KeyboardNavigationMixin(
- A11yMixin(
- FilterMixin(
- ColumnReorderingMixin(
- ColumnResizingMixin(
- EventContextMixin(DragAndDropMixin(StylingMixin(TabindexMixin(ResizeMixin(superClass))))),
+ ColumnRenderingMixin(
+ ActiveItemMixin(
+ ScrollMixin(
+ SelectionMixin(
+ SortMixin(
+ RowDetailsMixin(
+ KeyboardNavigationMixin(
+ A11yMixin(
+ FilterMixin(
+ ColumnReorderingMixin(
+ ColumnResizingMixin(
+ EventContextMixin(
+ DragAndDropMixin(StylingMixin(TabindexMixin(ResizeMixin(superClass)))),
+ ),
+ ),
),
),
),
@@ -351,7 +354,7 @@ export const GridMixin = (superClass) =>
updatePart(row, 'row', true);
updatePart(row, 'body-row', true);
if (this._columnTree) {
- this.__initRow(row, this._columnTree[this._columnTree.length - 1], 'body', false, true);
+ this.__initRow(row, this._columnTree[this._columnTree.length - 1], 'body', true);
}
rows.push(row);
}
@@ -444,11 +447,10 @@ export const GridMixin = (superClass) =>
* @param {!HTMLTableRowElement} row
* @param {!Array} columns
* @param {?string} section
- * @param {boolean} isColumnRow
* @param {boolean} noNotify
* @private
*/
- __initRow(row, columns, section = 'body', isColumnRow = false, noNotify = false) {
+ __initRow(row, columns, section = 'body', noNotify = false) {
const contentsFragment = document.createDocumentFragment();
iterateRowCells(row, (cell) => {
@@ -516,30 +518,6 @@ export const GridMixin = (superClass) =>
if (!noNotify) {
column._cells = [...column._cells];
}
- } else {
- // Header & footer
- const tagName = section === 'header' ? 'th' : 'td';
- if (isColumnRow || column.localName === 'vaadin-grid-column-group') {
- cell = column[`_${section}Cell`];
- if (!cell) {
- cell = this._createCell(tagName);
- }
- cell._column = column;
- row.appendChild(cell);
- column[`_${section}Cell`] = cell;
- } else {
- if (!column._emptyCells) {
- column._emptyCells = [];
- }
- cell = column._emptyCells.find((cell) => cell._vacant) || this._createCell(tagName);
- cell._column = column;
- row.appendChild(cell);
- if (column._emptyCells.indexOf(cell) === -1) {
- column._emptyCells.push(cell);
- }
- }
- updatePart(cell, 'cell', true);
- updatePart(cell, `${section}-cell`, true);
}
if (!cell._content.parentElement) {
@@ -549,10 +527,6 @@ export const GridMixin = (superClass) =>
cell._column = column;
});
- if (section !== 'body') {
- this.__debounceUpdateHeaderFooterRowVisibility(row);
- }
-
// Might be empty if only cache was used
this.appendChild(contentsFragment);
@@ -560,75 +534,6 @@ export const GridMixin = (superClass) =>
this._updateFirstAndLastColumnForRow(row);
}
- /**
- * @param {HTMLTableRowElement} row
- * @protected
- */
- __debounceUpdateHeaderFooterRowVisibility(row) {
- row.__debounceUpdateHeaderFooterRowVisibility = Debouncer.debounce(
- row.__debounceUpdateHeaderFooterRowVisibility,
- microTask,
- () => this.__updateHeaderFooterRowVisibility(row),
- );
- }
-
- /**
- * @param {HTMLTableRowElement} row
- * @protected
- */
- __updateHeaderFooterRowVisibility(row) {
- if (!row) {
- return;
- }
-
- const visibleRowCells = Array.from(row.children).filter((cell) => {
- const column = cell._column;
- if (column._emptyCells && column._emptyCells.indexOf(cell) > -1) {
- // The cell is an "empty cell" -> doesn't block hiding the row
- return false;
- }
- if (row.parentElement === this.$.header) {
- if (column.headerRenderer) {
- // The cell is the header cell of a column that has a header renderer
- // -> row should be visible
- return true;
- }
- if (column.header === null) {
- // The column header is explicilty set to null -> doesn't block hiding the row
- return false;
- }
- if (column.path || column.header !== undefined) {
- // The column has an explicit non-null header or a path that generates a header
- // -> row should be visible
- return true;
- }
- } else if (column.footerRenderer) {
- // The cell is the footer cell of a column that has a footer renderer
- // -> row should be visible
- return true;
- }
- return false;
- });
-
- if (row.hidden !== !visibleRowCells.length) {
- row.hidden = !visibleRowCells.length;
- }
-
- if (row.parentElement === this.$.header) {
- this.$.table.toggleAttribute('has-header', this.$.header.querySelector('tr:not([hidden])'));
- this.__updateHeaderFooterRowParts('header');
- }
-
- if (row.parentElement === this.$.footer) {
- this.$.table.toggleAttribute('has-footer', this.$.footer.querySelector('tr:not([hidden])'));
- this.__updateHeaderFooterRowParts('footer');
- }
-
- // Make sure the section has a tabbable element
- this._resetKeyboardNavigation();
- this.__a11yUpdateGridSize(this.size, this._columnTree, this.__emptyState);
- }
-
/** @private */
__updateVirtualizerElement(row, index) {
this._preventScrollerRotatingCellFocus(row, index);
@@ -681,43 +586,15 @@ export const GridMixin = (superClass) =>
*/
_renderColumnTree(columnTree) {
iterateChildren(this.$.items, (row) => {
- this.__initRow(row, columnTree[columnTree.length - 1], 'body', false, true);
+ this.__initRow(row, columnTree[columnTree.length - 1], 'body', true);
this.__updateRow(row);
});
- while (this.$.header.children.length < columnTree.length) {
- const headerRow = document.createElement('tr');
- headerRow.setAttribute('role', 'row');
- headerRow.setAttribute('tabindex', '-1');
- updatePart(headerRow, 'row', true);
- updatePart(headerRow, 'header-row', true);
- this.$.header.appendChild(headerRow);
-
- const footerRow = document.createElement('tr');
- footerRow.setAttribute('role', 'row');
- footerRow.setAttribute('tabindex', '-1');
- updatePart(footerRow, 'row', true);
- updatePart(footerRow, 'footer-row', true);
- this.$.footer.appendChild(footerRow);
- }
- while (this.$.header.children.length > columnTree.length) {
- this.$.header.removeChild(this.$.header.firstElementChild);
- this.$.footer.removeChild(this.$.footer.firstElementChild);
- }
-
- iterateChildren(this.$.header, (headerRow, index) => {
- this.__initRow(headerRow, columnTree[index], 'header', index === columnTree.length - 1);
- });
-
- iterateChildren(this.$.footer, (footerRow, index) => {
- this.__initRow(footerRow, columnTree[columnTree.length - 1 - index], 'footer', index === 0);
- });
+ this.__renderHeaderFooter();
// Sizer rows
this.__initRow(this.$.sizer, columnTree[columnTree.length - 1]);
- this.__updateHeaderFooterRowParts('header');
- this.__updateHeaderFooterRowParts('footer');
this._resizeHandler();
this._frozenCellsChanged();
this._updateFirstAndLastColumn();
@@ -739,6 +616,8 @@ export const GridMixin = (superClass) =>
updatePart(cell, `first-${section}-row-cell`, row === visibleRows.at(0));
updatePart(cell, `last-${section}-row-cell`, row === visibleRows.at(-1));
});
+
+ this._updateFirstAndLastColumnForRow(row);
});
}
diff --git a/packages/grid/src/vaadin-grid-sort-column-mixin.js b/packages/grid/src/vaadin-grid-sort-column-mixin.js
index 52bf4a5c058..5f209e2d5c2 100644
--- a/packages/grid/src/vaadin-grid-sort-column-mixin.js
+++ b/packages/grid/src/vaadin-grid-sort-column-mixin.js
@@ -46,16 +46,25 @@ export const GridSortColumnMixin = (superClass) =>
*/
_defaultHeaderRenderer(root, _column) {
let sorter = root.firstElementChild;
- if (!sorter) {
+ const isNewSorter = !sorter;
+ if (isNewSorter) {
sorter = document.createElement('vaadin-grid-sorter');
sorter.addEventListener('direction-changed', this.__boundOnDirectionChanged);
- root.appendChild(sorter);
}
sorter.path = this.path;
sorter.__rendererDirection = this.direction;
sorter.direction = this.direction;
sorter.textContent = this.__getHeader(this.header, this.path);
+
+ // Append the sorter only after its direction has been set. If the cell
+ // content is already connected (as with the declarative header rendering),
+ // appending an unconfigured sorter makes it notify its default `null`
+ // direction before `__rendererDirection` is set, which would reset the
+ // column's direction. See __onDirectionChanged.
+ if (isNewSorter) {
+ root.appendChild(sorter);
+ }
}
/**
diff --git a/packages/grid/test/column-groups.test.js b/packages/grid/test/column-groups.test.js
index e59e933d3df..f176840b5d7 100644
--- a/packages/grid/test/column-groups.test.js
+++ b/packages/grid/test/column-groups.test.js
@@ -328,7 +328,7 @@ describe('column groups', () => {
group.footerRenderer = attributeRenderer('footer');
});
- sinon.spy(grid, '__updateHeaderFooterRowVisibility');
+ sinon.spy(grid, '__renderHeaderFooter');
sinon.spy(grid, '_updateColumnTree');
grid.dataProvider = infiniteDataProvider;
flushGrid(grid);
@@ -336,12 +336,12 @@ describe('column groups', () => {
await nextResize(grid);
});
- it('should update header and footer rows visibility once', () => {
- // 6 header and footer rows are created
- expect(grid.__updateHeaderFooterRowVisibility.callCount).to.equal(6);
+ it('should not update header and footer rows too many times', () => {
+ // One from _updateColumnTree, another one from column observers
+ expect(grid.__renderHeaderFooter.callCount).to.equal(2);
});
- it('should update column tree once', () => {
+ it('should not update column tree too many times', () => {
expect(grid._updateColumnTree.callCount).to.equal(1);
});
diff --git a/packages/grid/test/column-resizing.test.js b/packages/grid/test/column-resizing.test.js
index 1f31518e99e..b087e8c75d6 100644
--- a/packages/grid/test/column-resizing.test.js
+++ b/packages/grid/test/column-resizing.test.js
@@ -174,6 +174,7 @@ describe('column resizing', () => {
it('should fix width for preceding columns', () => {
grid._columnTree[0][1].resizable = true;
+ flushGrid(grid);
grid._columnTree[0][0].width = '50%';
grid._columnTree[0][0].flexGrow = 1;
diff --git a/packages/grid/test/dom/__snapshots__/grid.test.snap.js b/packages/grid/test/dom/__snapshots__/grid.test.snap.js
index 051a5b8e442..f699d730e82 100644
--- a/packages/grid/test/dom/__snapshots__/grid.test.snap.js
+++ b/packages/grid/test/dom/__snapshots__/grid.test.snap.js
@@ -7,30 +7,30 @@ snapshots["vaadin-grid basic host default"] =
-
+
First
-
+
Last
-
+
-
+
-
+
-
+
-
+
Laura
-
+
Arnaud
-
+
Fabien
-
+
Le gall
@@ -61,25 +61,25 @@ snapshots["vaadin-grid basic shadow default"] =
-
+
-
+
@@ -100,25 +100,23 @@ snapshots["vaadin-grid basic shadow default"] =
-
+
-
+
@@ -145,26 +143,26 @@ snapshots["vaadin-grid basic shadow default"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell"
first-column=""
- id="vaadin-grid-cell-6"
+ id="vaadin-grid-cell-2"
part="cell body-cell first-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="0"
>
-
+
-
+
@@ -185,26 +183,26 @@ snapshots["vaadin-grid basic shadow default"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-row-cell odd-row-cell"
first-column=""
- id="vaadin-grid-cell-8"
+ id="vaadin-grid-cell-4"
part="cell body-cell first-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="-1"
>
-
+
-
+
@@ -236,31 +234,28 @@ snapshots["vaadin-grid basic shadow default"] =
hidden=""
part="row footer-row"
role="row"
- style="--_grid-horizontal-scroll-position: 0px;"
tabindex="-1"
>
-
+
-
+
@@ -306,25 +301,25 @@ snapshots["vaadin-grid basic shadow selected"] =
-
+
-
+
@@ -345,25 +340,23 @@ snapshots["vaadin-grid basic shadow selected"] =
-
+
-
+
@@ -391,26 +384,26 @@ snapshots["vaadin-grid basic shadow selected"] =
aria-selected="true"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell selected-row-cell"
first-column=""
- id="vaadin-grid-cell-6"
+ id="vaadin-grid-cell-2"
part="cell body-cell first-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell selected-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="0"
>
-
+
-
+
@@ -431,26 +424,26 @@ snapshots["vaadin-grid basic shadow selected"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-row-cell odd-row-cell"
first-column=""
- id="vaadin-grid-cell-8"
+ id="vaadin-grid-cell-4"
part="cell body-cell first-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="-1"
>
-
+
-
+
@@ -482,31 +475,28 @@ snapshots["vaadin-grid basic shadow selected"] =
hidden=""
part="row footer-row"
role="row"
- style="--_grid-horizontal-scroll-position: 0px;"
tabindex="-1"
>
-
+
-
+
@@ -552,25 +542,25 @@ snapshots["vaadin-grid basic shadow details opened"] =
-
+
-
+
@@ -591,25 +581,23 @@ snapshots["vaadin-grid basic shadow details opened"] =
-
+
-
+
@@ -636,26 +624,26 @@ snapshots["vaadin-grid basic shadow details opened"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell"
first-column=""
- id="vaadin-grid-cell-6"
+ id="vaadin-grid-cell-2"
part="cell body-cell first-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="0"
>
-
+
-
+
@@ -676,26 +664,26 @@ snapshots["vaadin-grid basic shadow details opened"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-row-cell odd-row-cell"
first-column=""
- id="vaadin-grid-cell-8"
+ id="vaadin-grid-cell-4"
part="cell body-cell first-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="-1"
>
-
+
-
+
@@ -727,31 +715,28 @@ snapshots["vaadin-grid basic shadow details opened"] =
hidden=""
part="row footer-row"
role="row"
- style="--_grid-horizontal-scroll-position: 0px;"
tabindex="-1"
>
-
+
-
+
@@ -797,14 +782,14 @@ snapshots["vaadin-grid basic shadow hidden column"] =
-
+
@@ -825,14 +810,13 @@ snapshots["vaadin-grid basic shadow hidden column"] =
-
+
@@ -859,14 +843,14 @@ snapshots["vaadin-grid basic shadow hidden column"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell last-column-cell"
first-column=""
- id="vaadin-grid-cell-7"
+ id="vaadin-grid-cell-3"
last-column=""
part="cell body-cell last-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="0"
>
-
+
@@ -887,14 +871,14 @@ snapshots["vaadin-grid basic shadow hidden column"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-column-cell last-row-cell odd-row-cell"
first-column=""
- id="vaadin-grid-cell-9"
+ id="vaadin-grid-cell-5"
last-column=""
part="cell body-cell last-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="-1"
>
-
+
@@ -926,20 +910,18 @@ snapshots["vaadin-grid basic shadow hidden column"] =
hidden=""
part="row footer-row"
role="row"
- style="--_grid-horizontal-scroll-position: 0px;"
tabindex="-1"
>
-
+
@@ -985,14 +967,14 @@ snapshots["vaadin-grid basic shadow hidden column selected"] =
-
+
@@ -1013,14 +995,13 @@ snapshots["vaadin-grid basic shadow hidden column selected"] =
-
+
@@ -1048,14 +1029,14 @@ snapshots["vaadin-grid basic shadow hidden column selected"] =
aria-selected="true"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell last-column-cell selected-row-cell"
first-column=""
- id="vaadin-grid-cell-7"
+ id="vaadin-grid-cell-3"
last-column=""
part="cell body-cell last-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell selected-row-cell first-column-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="0"
>
-
+
@@ -1076,14 +1057,14 @@ snapshots["vaadin-grid basic shadow hidden column selected"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-column-cell last-row-cell odd-row-cell"
first-column=""
- id="vaadin-grid-cell-9"
+ id="vaadin-grid-cell-5"
last-column=""
part="cell body-cell last-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="-1"
>
-
+
@@ -1115,20 +1096,18 @@ snapshots["vaadin-grid basic shadow hidden column selected"] =
hidden=""
part="row footer-row"
role="row"
- style="--_grid-horizontal-scroll-position: 0px;"
tabindex="-1"
>
-
+
@@ -1175,25 +1154,25 @@ snapshots["vaadin-grid basic shadow with footer"] =
-
+
-
+
@@ -1214,25 +1193,23 @@ snapshots["vaadin-grid basic shadow with footer"] =
-
+
-
+
@@ -1259,26 +1236,26 @@ snapshots["vaadin-grid basic shadow with footer"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell"
first-column=""
- id="vaadin-grid-cell-6"
+ id="vaadin-grid-cell-2"
part="cell body-cell first-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="0"
>
-
+
-
+
@@ -1299,26 +1276,26 @@ snapshots["vaadin-grid basic shadow with footer"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-row-cell odd-row-cell"
first-column=""
- id="vaadin-grid-cell-8"
+ id="vaadin-grid-cell-4"
part="cell body-cell first-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="-1"
>
-
+
-
+
@@ -1349,31 +1326,28 @@ snapshots["vaadin-grid basic shadow with footer"] =
class="first-footer-row footer-row last-footer-row row"
part="row footer-row first-footer-row last-footer-row"
role="row"
- style="--_grid-horizontal-scroll-position: 0px;"
tabindex="-1"
>
-
+
-
+
@@ -1420,25 +1394,25 @@ snapshots["vaadin-grid column groups default"] =
-
+
-
+
@@ -1461,21 +1435,20 @@ snapshots["vaadin-grid column groups default"] =
class="cell first-column-cell header-cell last-column-cell"
colspan="2"
first-column=""
- id="vaadin-grid-cell-0"
last-column=""
part="cell header-cell first-column-cell last-column-cell"
role="columnheader"
style="width: calc(200px); flex-grow: 2;"
tabindex="-1"
>
-
+
@@ -1528,26 +1499,26 @@ snapshots["vaadin-grid column groups default"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell"
first-column=""
- id="vaadin-grid-cell-8"
+ id="vaadin-grid-cell-2"
part="cell body-cell first-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="0"
>
-
+
-
+
@@ -1568,26 +1539,26 @@ snapshots["vaadin-grid column groups default"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-row-cell odd-row-cell"
first-column=""
- id="vaadin-grid-cell-10"
+ id="vaadin-grid-cell-4"
part="cell body-cell first-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="-1"
>
-
+
-
+
@@ -1624,25 +1595,23 @@ snapshots["vaadin-grid column groups default"] =
-
+
-
+
@@ -1659,14 +1628,13 @@ snapshots["vaadin-grid column groups default"] =
class="cell first-column-cell footer-cell last-column-cell"
colspan="2"
first-column=""
- id="vaadin-grid-cell-5"
last-column=""
part="cell footer-cell first-column-cell last-column-cell"
role="gridcell"
style="width: calc(200px); flex-grow: 2;"
tabindex="-1"
>
-
+
@@ -1706,14 +1674,13 @@ snapshots["vaadin-grid column groups with header"] =
class="cell first-column-cell first-header-row-cell header-cell last-column-cell"
colspan="2"
first-column=""
- id="vaadin-grid-cell-0"
last-column=""
part="cell header-cell first-column-cell last-column-cell first-header-row-cell"
role="columnheader"
style="width: calc(200px); flex-grow: 2;"
tabindex="-1"
>
-
+
@@ -1728,25 +1695,23 @@ snapshots["vaadin-grid column groups with header"] =
-
+
-
+
@@ -1771,25 +1736,23 @@ snapshots["vaadin-grid column groups with footer"] =
-
+
-
+
@@ -1805,14 +1768,13 @@ snapshots["vaadin-grid column groups with footer"] =
class="cell first-column-cell footer-cell last-column-cell last-footer-row-cell"
colspan="2"
first-column=""
- id="vaadin-grid-cell-5"
last-column=""
part="cell footer-cell first-column-cell last-column-cell last-footer-row-cell"
role="gridcell"
style="width: calc(200px); flex-grow: 2;"
tabindex="-1"
>
-
+
@@ -1843,14 +1805,14 @@ snapshots["vaadin-grid hidden column group with group header"] =
-
+
@@ -1871,14 +1833,13 @@ snapshots["vaadin-grid hidden column group with group header"] =
-
+
@@ -1888,20 +1849,18 @@ snapshots["vaadin-grid hidden column group with group header"] =
hidden=""
part="row header-row"
role="row"
- style="--_grid-horizontal-scroll-position: 0px;"
tabindex="-1"
>
-
+
@@ -1928,14 +1887,14 @@ snapshots["vaadin-grid hidden column group with group header"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell last-column-cell"
first-column=""
- id="vaadin-grid-cell-5"
+ id="vaadin-grid-cell-1"
last-column=""
part="cell body-cell first-column-cell last-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="0"
>
-
+
@@ -1956,14 +1915,14 @@ snapshots["vaadin-grid hidden column group with group header"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-column-cell last-row-cell odd-row-cell"
first-column=""
- id="vaadin-grid-cell-6"
+ id="vaadin-grid-cell-2"
last-column=""
part="cell body-cell first-column-cell last-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="-1"
>
-
+
@@ -1995,20 +1954,18 @@ snapshots["vaadin-grid hidden column group with group header"] =
hidden=""
part="row footer-row"
role="row"
- style="--_grid-horizontal-scroll-position: 0px;"
tabindex="-1"
>
-
+
@@ -2023,14 +1980,13 @@ snapshots["vaadin-grid hidden column group with group header"] =
-
+
@@ -2076,14 +2032,14 @@ snapshots["vaadin-grid hidden column group with group and column header"] =
-
+
@@ -2104,14 +2060,13 @@ snapshots["vaadin-grid hidden column group with group and column header"] =
-
+
@@ -2126,14 +2081,13 @@ snapshots["vaadin-grid hidden column group with group and column header"] =
-
+
@@ -2160,14 +2114,14 @@ snapshots["vaadin-grid hidden column group with group and column header"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell last-column-cell"
first-column=""
- id="vaadin-grid-cell-5"
+ id="vaadin-grid-cell-1"
last-column=""
part="cell body-cell first-column-cell last-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="0"
>
-
+
@@ -2188,14 +2142,14 @@ snapshots["vaadin-grid hidden column group with group and column header"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-column-cell last-row-cell odd-row-cell"
first-column=""
- id="vaadin-grid-cell-6"
+ id="vaadin-grid-cell-2"
last-column=""
part="cell body-cell first-column-cell last-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="-1"
>
-
+
@@ -2227,20 +2181,18 @@ snapshots["vaadin-grid hidden column group with group and column header"] =
hidden=""
part="row footer-row"
role="row"
- style="--_grid-horizontal-scroll-position: 0px;"
tabindex="-1"
>
-
+
@@ -2255,14 +2207,13 @@ snapshots["vaadin-grid hidden column group with group and column header"] =
-
+
@@ -2307,14 +2258,14 @@ snapshots["vaadin-grid hidden column group with group footer"] =
-
+
@@ -2335,14 +2286,13 @@ snapshots["vaadin-grid hidden column group with group footer"] =
-
+
@@ -2352,20 +2302,18 @@ snapshots["vaadin-grid hidden column group with group footer"] =
hidden=""
part="row header-row"
role="row"
- style="--_grid-horizontal-scroll-position: 0px;"
tabindex="-1"
>
-
+
@@ -2392,14 +2340,14 @@ snapshots["vaadin-grid hidden column group with group footer"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell even-row-cell first-column-cell first-row-cell last-column-cell"
first-column=""
- id="vaadin-grid-cell-5"
+ id="vaadin-grid-cell-1"
last-column=""
part="cell body-cell first-column-cell last-column-cell first-row-cell even-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="0"
>
-
+
@@ -2420,14 +2368,14 @@ snapshots["vaadin-grid hidden column group with group footer"] =
aria-selected="false"
class="body-cell cell drag-disabled-row-cell drop-disabled-row-cell first-column-cell last-column-cell last-row-cell odd-row-cell"
first-column=""
- id="vaadin-grid-cell-6"
+ id="vaadin-grid-cell-2"
last-column=""
part="cell body-cell first-column-cell last-column-cell last-row-cell odd-row-cell drag-disabled-row-cell drop-disabled-row-cell"
role="gridcell"
style="width: 100px; flex-grow: 1;"
tabindex="-1"
>
-
+
@@ -2459,20 +2407,18 @@ snapshots["vaadin-grid hidden column group with group footer"] =
hidden=""
part="row footer-row"
role="row"
- style="--_grid-horizontal-scroll-position: 0px;"
tabindex="-1"
>
-
+
@@ -2487,14 +2433,13 @@ snapshots["vaadin-grid hidden column group with group footer"] =
-
+
diff --git a/packages/grid/test/helpers.js b/packages/grid/test/helpers.js
index 061f9b5fcb0..5688fd9acfd 100644
--- a/packages/grid/test/helpers.js
+++ b/packages/grid/test/helpers.js
@@ -15,14 +15,9 @@ export const flushGrid = (grid) => {
grid._debouncerHiddenChanged,
grid._debouncerApplyCachedData,
grid.__debounceUpdateFrozenColumn,
+ grid.__renderHeaderFooterDebouncer,
].forEach((debouncer) => debouncer?.flush());
- [...grid.$.header.children, ...grid.$.footer.children].forEach((row) => {
- if (row.__debounceUpdateHeaderFooterRowVisibility) {
- row.__debounceUpdateHeaderFooterRowVisibility.flush();
- }
- });
-
grid.__virtualizer.flush();
grid.__preventScrollerRotatingCellFocusDebouncer?.flush();
grid.performUpdate?.();
diff --git a/packages/grid/test/keyboard-navigation-cell-button.test.js b/packages/grid/test/keyboard-navigation-cell-button.test.js
index 89418c6a473..68d21422dbf 100644
--- a/packages/grid/test/keyboard-navigation-cell-button.test.js
+++ b/packages/grid/test/keyboard-navigation-cell-button.test.js
@@ -98,6 +98,6 @@ describe('keyboard navigation - focus button mode', () => {
it('should not create a focusable div with role="button" inside the header cell', () => {
const headerCell = getHeaderCell(grid, 0);
- expect(headerCell.firstChild.localName).to.equal('slot');
+ expect(headerCell.firstElementChild.localName).to.equal('slot');
});
});