diff --git a/packages/devextreme/js/__internal/ui/collection/collection_widget.base.ts b/packages/devextreme/js/__internal/ui/collection/collection_widget.base.ts index a99fa324792e..2a4bdfa737f8 100644 --- a/packages/devextreme/js/__internal/ui/collection/collection_widget.base.ts +++ b/packages/devextreme/js/__internal/ui/collection/collection_widget.base.ts @@ -1444,7 +1444,7 @@ class CollectionWidget< return this._itemContainer(); } - _renderEmptyMessage(rootNodes?: TItem[]): void { + _renderEmptyMessage(rootNodes?: TItem[]): boolean { const { items: userItems = [], noDataText } = this.option(); const items = rootNodes ?? userItems; @@ -1455,7 +1455,6 @@ class CollectionWidget< this._$noData.remove(); // @ts-expect-error ts-error this._$noData = null; - this.setAria('label', undefined); } if (!hideNoData) { @@ -1471,6 +1470,8 @@ class CollectionWidget< } } this.$element().toggleClass(EMPTY_COLLECTION, !hideNoData); + + return !hideNoData; } _itemDXEventHandler( diff --git a/packages/devextreme/js/__internal/ui/list/list.base.ts b/packages/devextreme/js/__internal/ui/list/list.base.ts index 7e851d78a5d4..970fd478ac03 100644 --- a/packages/devextreme/js/__internal/ui/list/list.base.ts +++ b/packages/devextreme/js/__internal/ui/list/list.base.ts @@ -996,11 +996,18 @@ export class ListBase extends CollectionWidget { }; this.setAria(elementAria, this.$element()); - this.setAria({ role: 'application' }, this._focusTarget()); this._setListAria(); } + _renderEmptyMessage(rootNodes?: Item[]): boolean { + const isEmpty = super._renderEmptyMessage(rootNodes); + + this.setAria({ role: isEmpty ? undefined : 'application' }, this._focusTarget()); + + return isEmpty; + } + _isMultiSelectMode(): boolean { const { selectionMode } = this.option(); return selectionMode === 'multiple' || selectionMode === 'all'; diff --git a/packages/devextreme/js/__internal/ui/toolbar/toolbar.base.ts b/packages/devextreme/js/__internal/ui/toolbar/toolbar.base.ts index 26429ac5e56d..878ba732e30c 100644 --- a/packages/devextreme/js/__internal/ui/toolbar/toolbar.base.ts +++ b/packages/devextreme/js/__internal/ui/toolbar/toolbar.base.ts @@ -445,7 +445,9 @@ class ToolbarBase< this._applyCompactMode(); } - _renderEmptyMessage(): void {} + _renderEmptyMessage(): boolean { + return false; + } _clean(): void { this._$toolbarItemsContainer.children().empty(); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/lookup.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/lookup.tests.js index 7bfa2ea386fa..a55aba0d87d6 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/lookup.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/lookup.tests.js @@ -3734,7 +3734,6 @@ if(devices.real().deviceType === 'desktop') { const listItemContainerAttributes = { tabindex: searchEnabled ? '-1' : '0', - role: 'application', }; let fieldAttributes = { @@ -3891,7 +3890,7 @@ if(devices.real().deviceType === 'desktop') { const $scrollView = $list.find(`.${SCROLL_VIEW_CONTENT_CLASS}`); const $itemsContainer = $list.find(`.${LIST_ITEMS_CLASS}`); - helper.checkAttributes($scrollView, { tabindex: '-1', role: 'application' }); + helper.checkAttributes($scrollView, { tabindex: '-1' }); helper.checkAttributes($itemsContainer, { }); helper.widget.option(dataSourcePropertyName, [1, 2, 3]); @@ -3899,7 +3898,7 @@ if(devices.real().deviceType === 'desktop') { helper.checkAttributes($itemsContainer, { 'aria-label': 'Items', role: 'listbox' }); helper.widget.option(dataSourcePropertyName, []); - helper.checkAttributes($scrollView, { tabindex: '-1', role: 'application' }); + helper.checkAttributes($scrollView, { tabindex: '-1' }); helper.checkAttributes($itemsContainer, { }); }); }); diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/selectBox.tests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/selectBox.tests.js index 420efeba5a61..fc4136ec5b1f 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/selectBox.tests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets.editors/selectBox.tests.js @@ -6150,7 +6150,7 @@ if(devices.real().deviceType === 'desktop') { helper.checkAttributes(helper.widget._list.$element(), listAttributes, localizedRoleDescription); const $listItemContainer = helper.widget._list.$element().find(`.${SCROLLVIEW_CONTENT_CLASS}`); - helper.checkAttributes($listItemContainer, { role: 'application' }, 'scrollview content'); + helper.checkAttributes($listItemContainer, { }, 'scrollview content'); const inputAttributes = { autocomplete: 'off', @@ -6183,7 +6183,7 @@ if(devices.real().deviceType === 'desktop') { listAttributes.id = helper.widget._listId; helper.checkAttributes(helper.widget._list.$element(), listAttributes, 'list'); - helper.checkAttributes($listItemContainer, { role: 'application' }, 'scrollview content'); + helper.checkAttributes($listItemContainer, { }, 'scrollview content'); inputAttributes['aria-controls'] = helper.widget._listId; inputAttributes['aria-owns'] = helper.widget._popupContentId; diff --git a/packages/devextreme/testing/tests/DevExpress.ui.widgets/listParts/commonTests.js b/packages/devextreme/testing/tests/DevExpress.ui.widgets/listParts/commonTests.js index 9a742fb51e0f..03f55e328e24 100644 --- a/packages/devextreme/testing/tests/DevExpress.ui.widgets/listParts/commonTests.js +++ b/packages/devextreme/testing/tests/DevExpress.ui.widgets/listParts/commonTests.js @@ -5342,4 +5342,33 @@ QUnit.module('Accessibility', () => { 'checkbox aria-label updated after runtime change'); }); + [true, false].forEach(repaintChangesOnly => { + QUnit.test(`scrollview-content should not have role when dataSource is empty on init and repaintChangesOnly=${repaintChangesOnly} (T1329047)`, function(assert) { + const instance = $('#list').dxList({ dataSource: [], repaintChangesOnly }).dxList('instance'); + + assert.strictEqual(instance.$element().find(`.${SCROLLVIEW_CONTENT_CLASS}`).eq(0).attr('role'), undefined); + }); + + QUnit.test(`scrollview-content should have role="application" when dataSource has items on init and repaintChangesOnly=${repaintChangesOnly} (T1329047)`, function(assert) { + const instance = $('#list').dxList({ dataSource: ['Item 1'], repaintChangesOnly }).dxList('instance'); + + assert.strictEqual(instance.$element().find(`.${SCROLLVIEW_CONTENT_CLASS}`).eq(0).attr('role'), 'application'); + }); + + QUnit.test(`scrollview-content role should be removed when dataSource is cleared at runtime and repaintChangesOnly=${repaintChangesOnly} (T1329047)`, function(assert) { + const instance = $('#list').dxList({ dataSource: ['Item 1'], repaintChangesOnly }).dxList('instance'); + + instance.option('dataSource', []); + + assert.strictEqual(instance.$element().find(`.${SCROLLVIEW_CONTENT_CLASS}`).eq(0).attr('role'), undefined); + }); + + QUnit.test(`scrollview-content role should be restored when dataSource is set at runtime and repaintChangesOnly=${repaintChangesOnly} (T1329047)`, function(assert) { + const instance = $('#list').dxList({ dataSource: [], repaintChangesOnly }).dxList('instance'); + + instance.option('dataSource', ['Item 1']); + + assert.strictEqual(instance.$element().find(`.${SCROLLVIEW_CONTENT_CLASS}`).eq(0).attr('role'), 'application'); + }); + }); });