From 62d5fa0ab0fc5ae669f878df660c78c1150f524c Mon Sep 17 00:00:00 2001 From: didimmova Date: Tue, 16 Jun 2026 17:28:51 +0300 Subject: [PATCH 1/9] feat(grid): update grid border-related styles --- .../grid-summary/_grid-summary-theme.scss | 2 +- .../components/grid/_grid-component.scss | 4 ++ .../components/grid/_grid-derived-themes.scss | 17 ++++- .../styles/components/grid/_grid-theme.scss | 67 ++++++++++++------- 4 files changed, 63 insertions(+), 27 deletions(-) diff --git a/projects/igniteui-angular/core/src/core/styles/components/grid-summary/_grid-summary-theme.scss b/projects/igniteui-angular/core/src/core/styles/components/grid-summary/_grid-summary-theme.scss index 716d32d1ffc..51f95f417c5 100644 --- a/projects/igniteui-angular/core/src/core/styles/components/grid-summary/_grid-summary-theme.scss +++ b/projects/igniteui-angular/core/src/core/styles/components/grid-summary/_grid-summary-theme.scss @@ -44,7 +44,7 @@ outline-style: none; @if $variant == 'indigo' { - border-top: rem(1px) solid var-get($theme, 'border-color'); + border-top: var-get($theme, 'border-width') var-get($theme, 'border-style') var-get($theme, 'border-color'); } } diff --git a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-component.scss b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-component.scss index 44137c2010c..29463e45c6b 100644 --- a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-component.scss +++ b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-component.scss @@ -80,6 +80,10 @@ @extend %grid-scroll-start !optional; } + @include e(scroll-end) { + @extend %grid-scroll-end !optional; + } + @include e(scroll-main) { @extend %grid-scroll-main !optional; } diff --git a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-derived-themes.scss b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-derived-themes.scss index b0ccfd1633c..33dcf74c339 100644 --- a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-derived-themes.scss +++ b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-derived-themes.scss @@ -96,6 +96,21 @@ ) ); + igx-grid-group-by-area { + @include tokens( + chip-theme( + $schema: $schema, + $background: color-mix(in srgb, var(--ig-grid-header-text-color) 12%, var(--ig-grid-header-background)), + $text-color: var(--ig-grid-header-text-color), + $ghost-background: color-mix(in srgb, var(--ig-grid-header-text-color) 12%, var(--ig-grid-header-background)), + $ghost-text-color: var(--ig-grid-header-text-color), + $disabled-background: color-mix(in srgb, var(--ig-grid-header-text-color) 12%, var(--ig-grid-header-background)), + $disabled-text-color: color-mix(in srgb, var(--ig-grid-header-text-color) 50%, var(--ig-grid-header-background)), + $disabled-border-color: color-mix(in srgb, var(--ig-grid-header-text-color) 24%, var(--ig-grid-header-background)), + ) + ); + } + @include tokens( contained-button-theme( $schema: $schema, @@ -302,7 +317,7 @@ @include tokens( scrollbar-theme( $schema: $schema, - $sb-track-bg-color: var(--_grid-background, $scrollbar-bg-color), + $sb-track-bg-color: var(--_grid-background, var(--content-background), $scrollbar-bg-color), $sb-thumb-bg-color: var(--_scrollbar-thumb-color, $scrollbar-thumb-color), $sb-track-border-color: var(--_scrollbar-track-border-color, $scrollbar-track-border-color), ), diff --git a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss index 803c9376faa..195db313723 100644 --- a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss +++ b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss @@ -54,7 +54,10 @@ $grid-cell-pinned-style: rem(1px) solid; $grid-cell-pinned-border-color: color($color: 'gray', $variant: 300); - $grid-header-border: var-get($theme, 'header-border-width') var-get($theme, 'header-border-style') var-get($theme, 'header-border-color'); + $grid-header-border-color: if($variant == 'indigo', var-get($theme, 'header-border-color'), hsla(from var-get($theme, 'header-border-color') h s l / 0.38)); + $grid-header-border: var-get($theme, 'header-border-width') var-get($theme, 'header-border-style') $grid-header-border-color; + $grid-row-border: var-get($theme, 'row-border-width') var-get($theme, 'row-border-style') var-get($theme, 'row-border-color'); + $grid-scrollbar-borders: rem(1px) solid var(--ig-grid-summary-border-color, var(--row-border-color)); $cell-pin: ( style: var-get($theme, 'pinned-border-width') var-get($theme, 'pinned-border-style'), @@ -613,6 +616,14 @@ display: flex; overflow: hidden; + .igx-grid__tr-action:last-of-type { + border-inline-end: $grid-header-border; + } + + .igx-grid-th--pinned-last { + border-inline-end: var(--pinned-border-width) var(--pinned-border-style) var(--header-border-color) !important + } + %igx-grid__header-indentation { igx-icon { --component-size: #{if($variant == 'indigo', 2, 3)}; @@ -717,7 +728,6 @@ %grid-tfoot { grid-row: 5; - border-top: $grid-header-border; z-index: 10001; } @@ -765,8 +775,8 @@ @if $variant == 'indigo' { %grid-cell-display { - border-inline-end: rem(1px) solid var-get($theme, 'row-border-color'); - border-bottom: rem(1px) solid var-get($theme, 'row-border-color'); + border-inline-end: $grid-row-border; + border-bottom: $grid-row-border; } } } @@ -775,7 +785,7 @@ %igx-grid__hierarchical-expander, %igx-grid__row-indentation, %igx-grid__drag-indicator { - border-bottom: rem(1px) solid var-get($theme, 'row-border-color'); + border-bottom: $grid-row-border; } } @@ -823,26 +833,26 @@ display: flex; flex-flow: row nowrap; width: 100%; - background: var-get($theme, 'header-background'); + background: var-get($theme, 'content-background'); z-index: 10001; } %grid-thead-thumb { background: var-get($theme, 'header-background'); - border-inline-start: rem(1px) solid var-get($theme, 'header-border-color'); + border-inline-start: $grid-header-border; } %grid-tfoot-thumb { position: absolute; top: 0; inset-inline-end: 0; - background: var-get($theme, 'header-background'); - border-inline-start: rem(1px) solid var-get($theme, 'header-border-color'); + background: var(--_grid-background, var-get($theme, 'content-background')); + border-inline-start: $grid-scrollbar-borders; } %grid-tbody-scrollbar { background: var-get($theme, 'content-background'); - border-inline-start: rem(1px) solid var-get($theme, 'row-border-color'); + border-inline-start: $grid-scrollbar-borders; position: relative; } @@ -855,14 +865,18 @@ } %grid-tbody-scrollbar-end { - background: var-get($theme, 'header-background'); + background: var-get($theme, 'content-background'); } - %grid-scroll-start { - background: var-get($theme, 'header-background'); + %grid-scroll-start, + %grid-scroll-end { + background: var-get($theme, 'content-background'); + border-block-start: $grid-scrollbar-borders; } %grid-scroll-main { + border-block-start: $grid-scrollbar-borders; + igx-display-container { height: 0; } @@ -875,7 +889,7 @@ %grid-row { display: flex; background: var-get($theme, 'content-background'); - border-bottom: rem(1px) solid var-get($theme, 'row-border-color'); + border-bottom: $grid-row-border; outline-style: none; position: relative; background-clip: content-box !important; @@ -1825,13 +1839,11 @@ %grid-summaries--body { --summaries-patch-background: color-mix(in srgb, var(--_grid-foreground, var(--ig-gray-100)) 12%, var(--_grid-background, var(--ig-gray-100))); - border-bottom: rem(1px) dashed var-get($theme, 'row-border-color'); + border-bottom: var(--ig-grid-summary-border-width, rem(1px)) + dashed + var(--ig-grid-summary-border-color, var(--row-border-color)); background-color: var-get($theme, 'summaries-patch-background'); - &:last-of-type { - border-bottom: none; - } - .igx-grid-summary { --background-color: inherit; --result-color: #{adaptive-contrast(var(--background-color))}; @@ -1841,11 +1853,15 @@ %grid-summaries-patch { position: relative; background: inherit; - border-inline-end: rem(1px) solid var-get($theme, 'header-border-color'); + border-inline-end: var(--ig-grid-summary-border-width, rem(1px)) + var(--ig-grid-summary-border-style, solid) + var(--ig-grid-summary-border-color, var(--row-border-color)); z-index: 1; @if $variant == 'indigo' { - border-top: rem(1px) solid var-get($theme, 'header-border-color'); + border-top: var(--ig-grid-summary-border-width, rem(1px)) + var(--ig-grid-summary-border-style, solid) + var(--ig-grid-summary-border-color, var(--row-border-color)); } } @@ -1980,7 +1996,7 @@ background: var-get($theme, 'group-row-background'); display: flex; outline-style: none; - border-bottom: rem(1px) solid var-get($theme, 'row-border-color'); + border-block: $grid-row-border; min-height: var(--header-size); %igx-grid__drag-indicator { @@ -2119,7 +2135,7 @@ map.get($grid-grouping-indicator-padding, 'cosy'), map.get($grid-grouping-indicator-padding, 'comfortable') ); - border-inline-end: rem(1px) solid var-get($theme, 'header-border-color'); + border-inline-end: $grid-row-border; background: inherit; z-index: 1; background-clip: border-box; @@ -2585,7 +2601,7 @@ %igx-grid__tr-container { overflow: auto; width: 100%; - border-bottom: rem(1px) solid var-get($theme, 'row-border-color'); + border-bottom: $grid-row-border; } %igx-grid__tr-container--active { @@ -2714,7 +2730,8 @@ %igx-grid__tr-action { &:last-of-type { - border-inline-end: var-get($theme, 'header-border-width') var-get($theme, 'header-border-style') var-get($theme, 'header-border-color'); + border-inline-end: $grid-row-border; + @if $variant != 'indigo' { min-height: sizable( rem(32px), From b5f93a199db7da3d0045bd7c21749d48e8d7114a Mon Sep 17 00:00:00 2001 From: didimmova Date: Wed, 17 Jun 2026 12:44:06 +0300 Subject: [PATCH 2/9] fix(grid): fix scrollbar start background --- .../core/src/core/styles/components/grid/_grid-theme.scss | 2 +- .../igniteui-angular/grids/grid/src/grid.component.spec.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss index 195db313723..a7e84b13713 100644 --- a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss +++ b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss @@ -857,7 +857,7 @@ } %grid-tbody-scrollbar-start { - background: var-get($theme, 'header-background'); + background: var-get($theme, 'content-background'); } %grid-tbody-scrollbar-main { diff --git a/projects/igniteui-angular/grids/grid/src/grid.component.spec.ts b/projects/igniteui-angular/grids/grid/src/grid.component.spec.ts index 566a0bb7d50..92525f35484 100644 --- a/projects/igniteui-angular/grids/grid/src/grid.component.spec.ts +++ b/projects/igniteui-angular/grids/grid/src/grid.component.spec.ts @@ -384,7 +384,7 @@ describe('IgxGrid Component Tests #grid', () => { fixture.componentInstance.generateData(30); fixture.detectChanges(); tick(1000); - expect(parseInt(window.getComputedStyle(gridBody.nativeElement).height, 10)).toBe(548); + expect(parseInt(window.getComputedStyle(gridBody.nativeElement).height, 10)).toBe(549); // Check for empty filter grid message and body less than 100px const columns = fixture.componentInstance.grid.columnList; @@ -392,13 +392,13 @@ describe('IgxGrid Component Tests #grid', () => { fixture.detectChanges(); tick(100); expect(gridBody.nativeElement.textContent).toEqual(grid.emptyFilteredGridMessage); - expect(parseInt(window.getComputedStyle(gridBody.nativeElement).height, 10)).toBe(548); + expect(parseInt(window.getComputedStyle(gridBody.nativeElement).height, 10)).toBe(549); // Clear filter and check if grid's body height is restored based on all loaded rows grid.clearFilter(columns.get(0).field); fixture.detectChanges(); tick(100); - expect(parseInt(window.getComputedStyle(gridBody.nativeElement).height, 10)).toBe(548); + expect(parseInt(window.getComputedStyle(gridBody.nativeElement).height, 10)).toBe(549); // Clearing grid's data and check for empty grid message fixture.componentInstance.clearData(); From 63b0aa9fb73bb713c0a2c11720048542a4a3f991 Mon Sep 17 00:00:00 2001 From: didimmova Date: Wed, 17 Jun 2026 15:21:47 +0300 Subject: [PATCH 3/9] tests(grid): fix grid test after border changes --- .../grids/grid/src/cell-merge.spec.ts | 10 ++++++++++ .../igniteui-angular/grids/grid/src/cell.spec.ts | 7 +++++-- .../grids/grid/src/grid-row-pinning.spec.ts | 15 ++++++++------- .../grids/grid/src/grid.component.spec.ts | 8 ++++---- .../grids/grid/src/grid.groupby.spec.ts | 8 ++++++-- 5 files changed, 33 insertions(+), 15 deletions(-) diff --git a/projects/igniteui-angular/grids/grid/src/cell-merge.spec.ts b/projects/igniteui-angular/grids/grid/src/cell-merge.spec.ts index f86fc04879b..4fff785e486 100644 --- a/projects/igniteui-angular/grids/grid/src/cell-merge.spec.ts +++ b/projects/igniteui-angular/grids/grid/src/cell-merge.spec.ts @@ -1167,6 +1167,16 @@ describe('IgxGrid - Cell merging #grid', () => { await activeChange; await wait(20); fix.detectChanges(); + // eslint-disable-next-line no-console + console.log('merge-debug', { + childActiveNode: childGrid.navigation.activeNode, + childActiveNodeRow: childGrid.navigation.activeNode?.row, + childSelectionKeys: Array.from((childGrid as any).selectionService.selection?.keys() || []), + childCachedActiveIndexes: (childGrid as any)._activeRowIndexes, + childActiveIndexes: (childGrid as any).activeRowIndexes, + pipeTrigger: childGrid.pipeTrigger, + childSpans: childGrid.dataRowList.toArray().map(row => row.metaData?.cellMergeMeta?.get(childCol.field)?.rowSpan || 1) + }); GridFunctions.verifyColumnMergedState(childGrid, childCol, [ { value: 'Product A', span: 2 }, diff --git a/projects/igniteui-angular/grids/grid/src/cell.spec.ts b/projects/igniteui-angular/grids/grid/src/cell.spec.ts index e2b5859c7db..8eea76d92dc 100644 --- a/projects/igniteui-angular/grids/grid/src/cell.spec.ts +++ b/projects/igniteui-angular/grids/grid/src/cell.spec.ts @@ -202,10 +202,13 @@ describe('IgxGrid - Cell component #grid', () => { const lastCell = cells[cells.length - 1]; expect(GridFunctions.getValueFromCellElement(lastCell)).toEqual('990'); - // Calculate where the end of the cell is. Relative left position should equal the grid calculated width + const scrollbarBorderWidth = parseFloat(getComputedStyle( + grid.nativeElement.querySelector('.igx-grid__tbody-scrollbar') + ).getPropertyValue('border-inline-start-width')) || 0; + // Calculate where the end of the cell is. Relative left position should equal the grid calculated width. expect(lastCell.nativeElement.getBoundingClientRect().left + lastCell.nativeElement.offsetWidth + - grid.scrollSize).toEqual(parseInt(grid.width, 10)); + grid.scrollSize).toEqual(grid.calcWidth + scrollbarBorderWidth); })); it('should not reduce the width of last pinned cell when there is vertical scroll.', () => { diff --git a/projects/igniteui-angular/grids/grid/src/grid-row-pinning.spec.ts b/projects/igniteui-angular/grids/grid/src/grid-row-pinning.spec.ts index 17c07ad8fd6..552877521fd 100644 --- a/projects/igniteui-angular/grids/grid/src/grid-row-pinning.spec.ts +++ b/projects/igniteui-angular/grids/grid/src/grid-row-pinning.spec.ts @@ -19,6 +19,7 @@ describe('Row Pinning #grid', () => { const FIXED_ROW_CONTAINER = '.igx-grid__tr--pinned '; const CELL_CSS_CLASS = '.igx-grid__td'; const DEBOUNCE_TIME = 60; + const PINNED_ROW_HEIGHT_TOLERANCE = 2; let fix; let grid: IgxGridComponent; @@ -78,7 +79,7 @@ describe('Row Pinning #grid', () => { // 2 records pinned + 2px border expect(grid.pinnedRowHeight).toBe(2 * grid.renderedRowHeight + 2); const expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight; - expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1); + expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(PINNED_ROW_HEIGHT_TOLERANCE); }); it('should pin rows to bottom.', () => { @@ -117,7 +118,7 @@ describe('Row Pinning #grid', () => { // 2 records pinned + 2px border expect(grid.pinnedRowHeight).toBe(2 * grid.renderedRowHeight + 2); const expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight; - expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1); + expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(PINNED_ROW_HEIGHT_TOLERANCE); }); it('should allow pinning row at specified index via API.', () => { @@ -539,7 +540,7 @@ describe('Row Pinning #grid', () => { fix.detectChanges(); let expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight; - expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1); + expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(PINNED_ROW_HEIGHT_TOLERANCE); grid.filter('ID', 'B', IgxStringFilteringOperand.instance().condition('startsWith'), false); fix.detectChanges(); @@ -550,7 +551,7 @@ describe('Row Pinning #grid', () => { fix.detectChanges(); expect(grid.pinnedRowHeight).toBe(0); expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight; - expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1); + expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(PINNED_ROW_HEIGHT_TOLERANCE); }); it('should return correct filterData collection.', () => { @@ -1072,7 +1073,7 @@ describe('Row Pinning #grid', () => { // 1 records pinned + 2px border expect(grid.pinnedRowHeight).toBe(grid.renderedRowHeight + 2); const expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight; - expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1); + expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(PINNED_ROW_HEIGHT_TOLERANCE); }); it('should keep the scrollbar sizes correct when partially filtering out pinned records', () => { @@ -1084,7 +1085,7 @@ describe('Row Pinning #grid', () => { // 4 records pinned + 2px border expect(grid.pinnedRowHeight).toBe(4 * grid.renderedRowHeight + 2); let expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight; - expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1); + expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(PINNED_ROW_HEIGHT_TOLERANCE); grid.filter('ContactTitle', 'Owner', IgxStringFilteringOperand.instance().condition('contains'), false); fix.detectChanges(); @@ -1092,7 +1093,7 @@ describe('Row Pinning #grid', () => { // 2 records pinned + 2px border expect(grid.pinnedRowHeight).toBe(2 * grid.renderedRowHeight + 2); expectedHeight = parseInt(grid.height, 10) - grid.pinnedRowHeight - 18 - grid.theadRow.nativeElement.offsetHeight; - expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(1); + expect(grid.calcHeight - expectedHeight).toBeLessThanOrEqual(PINNED_ROW_HEIGHT_TOLERANCE); }); }); diff --git a/projects/igniteui-angular/grids/grid/src/grid.component.spec.ts b/projects/igniteui-angular/grids/grid/src/grid.component.spec.ts index 92525f35484..07b9e63e6c7 100644 --- a/projects/igniteui-angular/grids/grid/src/grid.component.spec.ts +++ b/projects/igniteui-angular/grids/grid/src/grid.component.spec.ts @@ -431,7 +431,7 @@ describe('IgxGrid Component Tests #grid', () => { fixture.componentInstance.generateData(30); fixture.detectChanges(); tick(1000); - expect(parseInt(window.getComputedStyle(gridBody.nativeElement).height, 10)).toBe(548); + expect(parseInt(window.getComputedStyle(gridBody.nativeElement).height, 10)).toBe(549); loadingIndicator = gridBody.query(By.css('.igx-grid__loading')); expect(loadingIndicator).toBeNull(); @@ -442,13 +442,13 @@ describe('IgxGrid Component Tests #grid', () => { fixture.detectChanges(); tick(100); expect(gridBody.nativeElement.textContent).not.toEqual(grid.emptyFilteredGridMessage); - expect(parseInt(window.getComputedStyle(gridBody.nativeElement).height, 10)).toBe(548); + expect(parseInt(window.getComputedStyle(gridBody.nativeElement).height, 10)).toBe(549); // Clear filter and check if grid's body height is restored based on all loaded rows grid.clearFilter(columns.get(0).field); fixture.detectChanges(); tick(100); - expect(parseInt(window.getComputedStyle(gridBody.nativeElement).height, 10)).toBe(548); + expect(parseInt(window.getComputedStyle(gridBody.nativeElement).height, 10)).toBe(549); // Clearing grid's data and check for empty grid message fixture.componentInstance.clearData(); @@ -661,7 +661,7 @@ describe('IgxGrid Component Tests #grid', () => { fixture.componentInstance.generateData(30); fixture.detectChanges(); tick(1000); - expect(parseInt(window.getComputedStyle(gridBodyContent.nativeElement).height, 10)).toBe(548); + expect(parseInt(window.getComputedStyle(gridBodyContent.nativeElement).height, 10)).toBe(549); loadingIndicator = gridBodyContent.query(By.css('.igx-grid__loading')); expect(loadingIndicator).toBeNull(); diff --git a/projects/igniteui-angular/grids/grid/src/grid.groupby.spec.ts b/projects/igniteui-angular/grids/grid/src/grid.groupby.spec.ts index 33fa9b4308e..50ccedbe2e1 100644 --- a/projects/igniteui-angular/grids/grid/src/grid.groupby.spec.ts +++ b/projects/igniteui-angular/grids/grid/src/grid.groupby.spec.ts @@ -1267,11 +1267,15 @@ describe('IgxGrid - GroupBy #grid', () => { // verify virtualization states - should be in last chunk const virtState = grid.verticalScrollContainer.state; - expect(virtState.startIndex).toBe(grid.dataView.length - virtState.chunkSize); + expect(virtState.startIndex + grid.rowList.length).toBe(grid.dataView.length); // verify last row is visible at bottom const lastRow = grid.gridAPI.get_row_by_index(grid.dataView.length - 1); - expect(lastRow.nativeElement.getBoundingClientRect().bottom).toBe(grid.tbody.nativeElement.getBoundingClientRect().bottom); + const rowBorderWidth = parseFloat(getComputedStyle(lastRow.nativeElement).borderBottomWidth) || 0; + const lastRowBottomOffset = Math.abs( + lastRow.nativeElement.getBoundingClientRect().bottom - grid.tbody.nativeElement.getBoundingClientRect().bottom + ); + expect(lastRowBottomOffset).toBe(rowBorderWidth * 2); }); From bcfa6767f59d8d6574b2a1a4cf61019a85bf9153 Mon Sep 17 00:00:00 2001 From: didimmova Date: Wed, 17 Jun 2026 15:58:30 +0300 Subject: [PATCH 4/9] chore(changelog): update changelog --- CHANGELOG.md | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 822d34d73d9..c5e6df5c44e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,69 @@ All notable changes for each version of this project will be documented in this file. +## 22.0.0 + +### New Features + +- **Theming** + - Added derived themes for the Grid and related internal components. When a parent component theme is included, its internal controls now derive their tokens from the parent theme colors, keeping nested buttons, icons, inputs, dropdowns, checkboxes, scrollbars, chips, and other helper components visually aligned. + + - The derived themes are introduces for the following components: + - Grid + - Excel Filtering + - Grid Toolbar + - Paginator + - Column Actions + - Query Builder and Advanced Filtering Dialog + + - The derived themes are applied through the existing component theme mixins, so no additional mixin call is required. To style the whole `IgxGrid`, provide the `$background`, `$foreground`, and `$accent-color` properties to `grid-theme()` and include the generated theme with `tokens()`. The `$foreground` property is optional; when omitted, it is derived automatically as a contrast color for the background. Internal components inherit derived tokens from the parent component theme. + + You can also style each compound component inside the grid with its own theme by providing the same color properties. The generated tokens are scoped to that component and affect the nested controls inside it. + + ```scss + $grid-theme: grid-theme( + $schema: $schema, + $background: #ffffff, + $foreground: #1f2937, + $accent-color: #0061a8 + ); + + $excel-filtering-theme: excel-filtering-theme( + $schema: $schema, + $background: #ff2323, + $accent-color: #21fc9a + ); + + $query-builder-theme: query-builder-theme( + $schema: $schema, + $background: #f235ff, + $accent-color: #89a800 + ); + + $grid-toolbar-theme: grid-toolbar-theme( ... ); + + $paginator-theme: paginator-theme( ... ); + + $column-actions-theme: column-actions-theme( ... ); + + igx-grid { + @include tokens($grid-theme); + } + + igx-grid-excel-style-filtering, + .igx-excel-filter__secondary { + @include tokens($excel-filtering-theme); + } + + igx-advanced-filtering-dialog { + @include tokens($query-builder-theme); + } + + ... + ``` + + - Added a dedicated `excel-filtering-theme()` for styling the `Excel Style Filtering`. Use it instead of the excel-filtering color properties from `grid-theme()`. + ## 21.2.0 ### New Features From a753767d8e40d8e613ec6153b50cca875702937f Mon Sep 17 00:00:00 2001 From: didimmova Date: Wed, 17 Jun 2026 15:59:32 +0300 Subject: [PATCH 5/9] fix(query-builder): fix query builder derived themes input --- .../_query-builder-derived-themes.scss | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/projects/igniteui-angular/core/src/core/styles/components/query-builder/_query-builder-derived-themes.scss b/projects/igniteui-angular/core/src/core/styles/components/query-builder/_query-builder-derived-themes.scss index 661e5c54a07..85db73f1444 100644 --- a/projects/igniteui-angular/core/src/core/styles/components/query-builder/_query-builder-derived-themes.scss +++ b/projects/igniteui-angular/core/src/core/styles/components/query-builder/_query-builder-derived-themes.scss @@ -97,35 +97,35 @@ @include tokens( input-group-theme( $schema: $schema, - $box-background: var(--_grid-background), - $search-background: color-mix(in srgb, var(--_grid-foreground) 6%, var(--_grid-background)), - $idle-bottom-line-color: var(--_grid-accent-color), - $idle-secondary-color: var(--_grid-foreground), - $focused-secondary-color: var(--_grid-accent-color), - $border-color: var(--_grid-accent-color), - $idle-text-color: var(--_grid-foreground), - $placeholder-color: color-mix(in srgb, var(--_grid-foreground) 80%, var(--_grid-background)), + $box-background: var(--_query-builder-background), + $search-background: color-mix(in srgb, var(--_query-builder-foreground) 6%, var(--_query-builder-background)), + $idle-bottom-line-color: var(--_query-builder-accent-color), + $idle-secondary-color: var(--_query-builder-foreground), + $focused-secondary-color: var(--_query-builder-accent-color), + $border-color: var(--_query-builder-accent-color), + $idle-text-color: var(--_query-builder-foreground), + $placeholder-color: color-mix(in srgb, var(--_query-builder-foreground) 80%, var(--_query-builder-background)), ) ); } @else if $variant == 'indigo' { @include tokens( input-group-theme( $schema: $schema, - $idle-bottom-line-color: var(--_grid-accent-color), - $idle-text-color: var(--_grid-foreground), - $placeholder-color: color-mix(in srgb, var(--_grid-foreground) 80%, var(--_grid-background)), + $idle-bottom-line-color: var(--_query-builder-accent-color), + $idle-text-color: var(--_query-builder-foreground), + $placeholder-color: color-mix(in srgb, var(--_query-builder-foreground) 80%, var(--_query-builder-background)), ) ); } @else { @include tokens( input-group-theme( $schema: $schema, - $border-color: var(--_grid-accent-color), - $idle-text-color: var(--_grid-foreground), - $placeholder-color: color-mix(in srgb, var(--_grid-foreground) 80%, var(--_grid-background)), - $input-prefix-background: var(--_grid-accent-color), + $border-color: var(--_query-builder-accent-color), + $idle-text-color: var(--_query-builder-foreground), + $placeholder-color: color-mix(in srgb, var(--_query-builder-foreground) 80%, var(--_query-builder-background)), + $input-prefix-background: var(--_query-builder-accent-color), $border-disabled-background: transparent, - $disabled-border-color: color-mix(in srgb, var(--_grid-accent-color) 50%, transparent), + $disabled-border-color: color-mix(in srgb, var(--_query-builder-accent-color) 50%, transparent), ) ); } From 97149a3addcf5f90b30b70aa122d277a7bd9c089 Mon Sep 17 00:00:00 2001 From: didimmova Date: Thu, 18 Jun 2026 10:34:53 +0300 Subject: [PATCH 6/9] feat(grid): use action-border-color property --- .../core/src/core/styles/components/grid/_grid-theme.scss | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss index 4dd499a681c..cc4374e52e1 100644 --- a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss +++ b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss @@ -55,6 +55,7 @@ $grid-cell-pinned-border-color: color($color: 'gray', $variant: 300); $grid-header-border-color: if($variant == 'indigo', var-get($theme, 'header-border-color'), hsla(from var-get($theme, 'header-border-color') h s l / 0.38)); + $grid-action-border-color: if($variant == 'indigo', var-get($theme, 'action-border-color'), hsla(from var-get($theme, 'action-border-color') h s l / 0.38)); $grid-header-border: var-get($theme, 'header-border-width') var-get($theme, 'header-border-style') $grid-header-border-color; $grid-row-border: var-get($theme, 'row-border-width') var-get($theme, 'row-border-style') var-get($theme, 'row-border-color'); $grid-scrollbar-borders: rem(1px) solid var(--ig-grid-summary-border-color, var(--row-border-color)); @@ -2730,7 +2731,7 @@ %igx-grid__tr-action { &:last-of-type { - border-inline-end: $grid-row-border; + border-inline-end: var-get($theme, 'row-border-width') var-get($theme, 'row-border-style') $grid-action-border-color; @if $variant != 'indigo' { min-height: sizable( From 302c34964133572c842577ff96ff133054d30a61 Mon Sep 17 00:00:00 2001 From: didimmova Date: Thu, 18 Jun 2026 11:49:04 +0300 Subject: [PATCH 7/9] fix(grid): fix pinned border in grid --- .../core/src/core/styles/components/grid/_grid-theme.scss | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss index cc4374e52e1..a3dc9143a82 100644 --- a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss +++ b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss @@ -621,8 +621,12 @@ border-inline-end: $grid-header-border; } + .igx-grid-th--pinned-first { + border-inline-start: var(--pinned-border-width) var(--pinned-border-style) var(--header-border-color) !important; + } + .igx-grid-th--pinned-last { - border-inline-end: var(--pinned-border-width) var(--pinned-border-style) var(--header-border-color) !important + border-inline-end: var(--pinned-border-width) var(--pinned-border-style) var(--header-border-color) !important; } %igx-grid__header-indentation { From 6607b1b7514a3833dbcb8a1ee2ed03dd3b756515 Mon Sep 17 00:00:00 2001 From: didimmova Date: Thu, 18 Jun 2026 13:35:38 +0300 Subject: [PATCH 8/9] feat(grid): fix chips in header and mrl borders --- .../components/grid/_grid-derived-themes.scss | 4 +++- .../core/styles/components/grid/_grid-theme.scss | 13 ++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-derived-themes.scss b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-derived-themes.scss index 33dcf74c339..44291ab46a5 100644 --- a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-derived-themes.scss +++ b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-derived-themes.scss @@ -96,11 +96,13 @@ ) ); - igx-grid-group-by-area { + igx-grid-group-by-area, + igx-grid-header-row { @include tokens( chip-theme( $schema: $schema, $background: color-mix(in srgb, var(--ig-grid-header-text-color) 12%, var(--ig-grid-header-background)), + $hover-background: color-mix(in srgb, var(--ig-grid-header-text-color) 18%, var(--ig-grid-header-background)), $text-color: var(--ig-grid-header-text-color), $ghost-background: color-mix(in srgb, var(--ig-grid-header-text-color) 12%, var(--ig-grid-header-background)), $ghost-text-color: var(--ig-grid-header-text-color), diff --git a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss index a3dc9143a82..2295bc01c7a 100644 --- a/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss +++ b/projects/igniteui-angular/core/src/core/styles/components/grid/_grid-theme.scss @@ -610,6 +610,13 @@ %grid-row { border-bottom: none; } + + %grid-mrl-block { + %grid-cell-display { + border-inline-end: $grid-header-border; + border-bottom: $grid-header-border; + } + } } %grid-thead-container { @@ -656,7 +663,7 @@ %igx-grid__header-indentation, %igx-grid__row-indentation, %grid__cbx-selection { - border-bottom: var-get($theme, 'header-border-width') var-get($theme, 'header-border-style') var-get($theme, 'header-border-color'); + border-bottom: $grid-header-border; } } @@ -769,8 +776,8 @@ } %grid-cell-display { - border-inline-end: rem(1px) solid var-get($theme, 'header-border-color'); - border-bottom: rem(1px) solid var-get($theme, 'header-border-color'); + border-inline-end: $grid-row-border; + border-bottom: $grid-row-border; } } From f8da2d3bb8cd5d1a6300d0895413168c80c9836d Mon Sep 17 00:00:00 2001 From: Simeon Simeonoff Date: Thu, 18 Jun 2026 15:43:48 +0300 Subject: [PATCH 9/9] deps: update theming to latest version --- package-lock.json | 8 ++++---- package.json | 2 +- projects/igniteui-angular/package.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8d0a6745ce1..c89bc4b4b8e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "express": "^5.2.1", "fflate": "^0.8.1", "igniteui-i18n-core": "^1.0.2", - "igniteui-theming": "^27.2.0", + "igniteui-theming": "^27.3.0", "igniteui-trial-watermark": "^3.1.0", "jspdf": "^4.2.1", "lodash-es": "^4.17.21", @@ -14611,9 +14611,9 @@ } }, "node_modules/igniteui-theming": { - "version": "27.2.0", - "resolved": "https://registry.npmjs.org/igniteui-theming/-/igniteui-theming-27.2.0.tgz", - "integrity": "sha512-XGI8MIP2x2RO6yuiAkGHJHbocixPPGoAUQyFOxMgNWWqqGtEEM5OYAkzzKBNjJKWgbrmIMWTXtlIzd8yPV5qjQ==", + "version": "27.3.0", + "resolved": "https://registry.npmjs.org/igniteui-theming/-/igniteui-theming-27.3.0.tgz", + "integrity": "sha512-9xpPZkMUBSBzA1KzBoXurx61RoaUKW7p/H6CWks+Nh8SehsvAj2j4DSQlT0IR6bb41kRICYVNuyTqMicqLmaLA==", "license": "MIT", "dependencies": { "@modelcontextprotocol/sdk": "^1.28.0", diff --git a/package.json b/package.json index e3d69cd71c4..25bc18241ee 100644 --- a/package.json +++ b/package.json @@ -82,7 +82,7 @@ "express": "^5.2.1", "fflate": "^0.8.1", "igniteui-i18n-core": "^1.0.2", - "igniteui-theming": "^27.2.0", + "igniteui-theming": "^27.3.0", "igniteui-trial-watermark": "^3.1.0", "jspdf": "^4.2.1", "lodash-es": "^4.17.21", diff --git a/projects/igniteui-angular/package.json b/projects/igniteui-angular/package.json index 8ed6f974008..6af7f9188f8 100644 --- a/projects/igniteui-angular/package.json +++ b/projects/igniteui-angular/package.json @@ -75,7 +75,7 @@ "igniteui-trial-watermark": "^3.1.0", "jspdf": "^4.2.1", "lodash-es": "^4.17.21", - "igniteui-theming": "^27.2.0", + "igniteui-theming": "^27.3.0", "igniteui-i18n-core": "^1.0.5", "@igniteui/material-icons-extended": "^3.1.0" },