From 0545f1f31803831c9a9bcc5e83ae7cd4dba29923 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Wed, 27 May 2026 12:45:48 +0200 Subject: [PATCH 01/18] fix(grid): Add aria-selected attribute handling for single select rows --- packages/components/grid/src/grid.spec.ts | 71 +++++++++++++++++++++++ packages/components/grid/src/grid.ts | 16 ++++- 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/packages/components/grid/src/grid.spec.ts b/packages/components/grid/src/grid.spec.ts index cd0e5fc356..089247f05f 100644 --- a/packages/components/grid/src/grid.spec.ts +++ b/packages/components/grid/src/grid.spec.ts @@ -105,6 +105,14 @@ describe('sl-grid', () => { expect(rowIndices).to.deep.equal(['1', '2']); }); + + it('should not have aria-selected when selects is not set', () => { + const rows = el.renderRoot.querySelectorAll('tbody tr'); + + rows.forEach(row => { + expect(row).not.to.have.attribute('aria-selected'); + }); + }); }); describe('multiple select', () => { @@ -517,6 +525,42 @@ describe('sl-grid', () => { expect(el.dataSource?.selects).to.equal('single'); }); + + it('should have aria-selected="false" on all rows by default', () => { + const rows = el.renderRoot.querySelectorAll('tbody tr'); + + rows.forEach(row => { + expect(row).to.have.attribute('aria-selected', 'false'); + }); + }); + + it('should set aria-selected="true" on the selected row', async () => { + el.renderRoot + .querySelector('tbody tr:first-of-type td:last-of-type') + ?.click(); + await new Promise(resolve => setTimeout(resolve)); + + const row = el.renderRoot.querySelector('tbody tr:first-of-type'); + expect(row).to.have.attribute('aria-selected', 'true'); + }); + + it('should set aria-selected="false" on deselected rows when selection changes', async () => { + el.renderRoot + .querySelector('tbody tr:first-of-type td:last-of-type') + ?.click(); + await new Promise(resolve => setTimeout(resolve)); + + el.renderRoot + .querySelector('tbody tr:nth-of-type(2) td:last-of-type') + ?.click(); + await new Promise(resolve => setTimeout(resolve)); + + const firstRow = el.renderRoot.querySelector('tbody tr:first-of-type'), + secondRow = el.renderRoot.querySelector('tbody tr:nth-of-type(2)'); + + expect(firstRow).to.have.attribute('aria-selected', 'false'); + expect(secondRow).to.have.attribute('aria-selected', 'true'); + }); }); describe('row action activate', () => { @@ -585,6 +629,33 @@ describe('sl-grid', () => { expect(onActiveRowChange).to.have.been.calledOnce; expect(onActiveRowChange.firstCall.args[0].detail).to.deep.equal(el.items!.at(1)); }); + + it('should have aria-selected="false" on all rows by default', () => { + const rows = el.renderRoot.querySelectorAll('tbody tr'); + + rows.forEach(row => { + expect(row).to.have.attribute('aria-selected', 'false'); + }); + }); + + it('should set aria-selected="true" on the active row', async () => { + el.renderRoot.querySelector('tbody tr:last-of-type')?.click(); + await new Promise(resolve => setTimeout(resolve)); + + const row = el.renderRoot.querySelector('tbody tr:last-of-type'); + expect(row).to.have.attribute('aria-selected', 'true'); + }); + + it('should set aria-selected="false" when the row is deactivated', async () => { + el.renderRoot.querySelector('tbody tr:last-of-type')?.click(); + await new Promise(resolve => setTimeout(resolve)); + + el.renderRoot.querySelector('tbody tr:last-of-type')?.click(); + await new Promise(resolve => setTimeout(resolve)); + + const row = el.renderRoot.querySelector('tbody tr:last-of-type'); + expect(row).to.have.attribute('aria-selected', 'false'); + }); }); describe('row action select', () => { diff --git a/packages/components/grid/src/grid.ts b/packages/components/grid/src/grid.ts index 89498877b3..4fec0ed052 100644 --- a/packages/components/grid/src/grid.ts +++ b/packages/components/grid/src/grid.ts @@ -594,15 +594,26 @@ export class Grid extends ScopedElementsMixin(LitElement) { renderItemRow(item: ListDataSourceDataItem, index: number): TemplateResult { const rows = this.#headerRows, + active = this.activeRow === item.data, selected = this.dataSource?.isSelected(item), parts = [ 'row', index % 2 === 0 ? 'odd' : 'even', ...(selected ? ['selected'] : []), - ...(this.activeRow === item.data ? ['active'] : []), + ...(active ? ['active'] : []), ...(this.#dragItem === item ? ['dragging'] : []), ...(this.itemParts?.(item.data)?.split(' ') || []) - ]; + ], + ariaSelected = + this.selects === 'single' + ? selected + ? 'true' + : 'false' + : this.rowAction === 'activate' + ? active + ? 'true' + : 'false' + : nothing; return html` extends ScopedElementsMixin(LitElement) { @dragend=${(event: DragEvent) => this.#onDragEnd(event, item)} @drop=${(event: DragEvent) => this.#onDrop(event, item)} aria-rowindex=${index + 1} + aria-selected=${ariaSelected} index=${index} part=${parts.join(' ')}> ${rows[rows.length - 1].map(col => col.renderData(item))} From 73f7e268af4a5550d88a5647e6560b1a64247dc6 Mon Sep 17 00:00:00 2001 From: anna-lach Date: Thu, 28 May 2026 07:10:04 +0200 Subject: [PATCH 02/18] Changes after Copilot review --- packages/components/grid/src/grid.spec.ts | 39 +++++++++++++++++++++++ packages/components/grid/src/grid.ts | 2 +- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/packages/components/grid/src/grid.spec.ts b/packages/components/grid/src/grid.spec.ts index 089247f05f..96ffd2a796 100644 --- a/packages/components/grid/src/grid.spec.ts +++ b/packages/components/grid/src/grid.spec.ts @@ -563,6 +563,45 @@ describe('sl-grid', () => { }); }); + describe('single select via data source', () => { + beforeEach(async () => { + const ds = new ArrayListDataSource( + [ + { firstName: 'John', lastName: 'Doe' }, + { firstName: 'Jane', lastName: 'Smith' } + ], + { selects: 'single' } + ); + + el = await fixture(html` + + + + + `); + + await waitForGridToRenderData(el); + }); + + it('should have aria-selected="false" on all rows by default', () => { + const rows = el.renderRoot.querySelectorAll('tbody tr'); + + rows.forEach(row => { + expect(row).to.have.attribute('aria-selected', 'false'); + }); + }); + + it('should set aria-selected="true" on the selected row', async () => { + el.renderRoot + .querySelector('tbody tr:first-of-type td:last-of-type') + ?.click(); + await new Promise(resolve => setTimeout(resolve)); + + const row = el.renderRoot.querySelector('tbody tr:first-of-type'); + expect(row).to.have.attribute('aria-selected', 'true'); + }); + }); + describe('row action activate', () => { beforeEach(async () => { el = await fixture(html` diff --git a/packages/components/grid/src/grid.ts b/packages/components/grid/src/grid.ts index 4fec0ed052..6721daf1cb 100644 --- a/packages/components/grid/src/grid.ts +++ b/packages/components/grid/src/grid.ts @@ -605,7 +605,7 @@ export class Grid extends ScopedElementsMixin(LitElement) { ...(this.itemParts?.(item.data)?.split(' ') || []) ], ariaSelected = - this.selects === 'single' + (this.dataSource?.selects ?? this.selects) === 'single' ? selected ? 'true' : 'false' From b8dd60b51dddc9447fb0afa0bcd91774fea7b75f Mon Sep 17 00:00:00 2001 From: anna-lach Date: Thu, 28 May 2026 10:11:25 +0200 Subject: [PATCH 03/18] remove unnecessary formatting changes --- packages/components/button/CHANGELOG.md | 5 +++++ packages/components/combobox/CHANGELOG.md | 5 +++++ packages/components/form/CHANGELOG.md | 1 + packages/components/grid/CHANGELOG.md | 6 ++++++ packages/components/listbox/CHANGELOG.md | 1 + packages/components/menu/CHANGELOG.md | 2 ++ packages/components/paginator/CHANGELOG.md | 3 +++ packages/components/shared/CHANGELOG.md | 6 ++++++ packages/components/text-field/CHANGELOG.md | 2 ++ packages/themes/bingel-dc/CHANGELOG.md | 9 +++++++++ packages/themes/bingel-int/CHANGELOG.md | 9 +++++++++ packages/themes/clickedu/CHANGELOG.md | 9 +++++++++ packages/themes/editorial-suite/CHANGELOG.md | 8 ++++++++ packages/themes/itslearning/CHANGELOG.md | 9 +++++++++ packages/themes/kampus/CHANGELOG.md | 9 +++++++++ packages/themes/magister/CHANGELOG.md | 9 +++++++++ packages/themes/max/CHANGELOG.md | 9 +++++++++ packages/themes/my-digital-book/CHANGELOG.md | 8 ++++++++ packages/themes/myvanin_onhold/CHANGELOG.md | 4 ++++ packages/themes/neon/CHANGELOG.md | 9 +++++++++ packages/themes/sanoma-learning/CHANGELOG.md | 8 ++++++++ packages/themes/teas/CHANGELOG.md | 9 +++++++++ packages/themes/tig/CHANGELOG.md | 2 ++ 23 files changed, 142 insertions(+) diff --git a/packages/components/button/CHANGELOG.md b/packages/components/button/CHANGELOG.md index e4b840d17d..dc65913741 100644 --- a/packages/components/button/CHANGELOG.md +++ b/packages/components/button/CHANGELOG.md @@ -9,10 +9,12 @@ ### Patch Changes - [#3299](https://github.com/sl-design-system/components/pull/3299) [`78e7333`](https://github.com/sl-design-system/components/commit/78e733338fd67ef59797b3e02b22907fe0f5c638) - Minor style fixes: + - fix icon-only size regression by using `box-sizing: content-box` - fix `