From 73851f7e698092ddddba921de5fc9edc92363951 Mon Sep 17 00:00:00 2001 From: Milan Wanielik Date: Wed, 29 Oct 2025 21:46:19 +0100 Subject: [PATCH 1/8] fix: set DBTabItem selected state correctly Set (aria-)selected state via listener on parent tablist to also react on de-selection of item. --- .../src/components/tab-item/tab-item.lite.tsx | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/components/src/components/tab-item/tab-item.lite.tsx b/packages/components/src/components/tab-item/tab-item.lite.tsx index ef8888f60607..25869f00d11a 100644 --- a/packages/components/src/components/tab-item/tab-item.lite.tsx +++ b/packages/components/src/components/tab-item/tab-item.lite.tsx @@ -27,6 +27,7 @@ useDefaultProps({}); export default function DBTabItem(props: DBTabItemProps) { const _ref = useRef(null); + // jscpd:ignore-start const state = useStore({ _selected: false, @@ -49,18 +50,6 @@ export default function DBTabItem(props: DBTabItemProps) { props.onChange(event); } - // We have different ts types in different frameworks, so we need to use any here - - useTarget({ - stencil: () => { - const selected = (event.target as any)?.['checked']; - state._selected = getBooleanAsString(selected); - }, - default: () => { - state._selected = (event.target as any)?.['checked']; - } - }); - useTarget({ angular: () => handleFrameworkEventAngular(state, event, 'checked'), @@ -82,6 +71,14 @@ export default function DBTabItem(props: DBTabItemProps) { useTarget({ react: () => state.handleNameAttribute() }); state.initialized = false; + + // deselect this tab when another tab in tablist is selected + _ref.closest('[role=tablist]')?.addEventListener( + 'change', + (event: any) => { + state._selected = event.target === _ref; + } + ); } }, [_ref, state.initialized]); From ee4f087f26920c0c7ccb6481bb86931df48c0049 Mon Sep 17 00:00:00 2001 From: Milan Wanielik Date: Thu, 30 Oct 2025 17:19:39 +0100 Subject: [PATCH 2/8] chore: update DBTab test use var instead of file to hold click event results for test duration --- .../components/src/components/tabs/tabs.spec.tsx | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/packages/components/src/components/tabs/tabs.spec.tsx b/packages/components/src/components/tabs/tabs.spec.tsx index 3f5b36028b53..6a8546168b27 100644 --- a/packages/components/src/components/tabs/tabs.spec.tsx +++ b/packages/components/src/components/tabs/tabs.spec.tsx @@ -1,7 +1,6 @@ import AxeBuilder from '@axe-core/playwright'; import { expect, test } from '@playwright/experimental-ct-react'; -import { existsSync, rmSync, writeFileSync } from 'node:fs'; import { DBTabs } from './index'; // @ts-ignore - vue can only find it with .ts as file ending import { DEFAULT_VIEWPORT } from '../../shared/constants.ts'; @@ -9,13 +8,10 @@ import { DBTabItem } from '../tab-item'; import { DBTabList } from '../tab-list'; import { DBTabPanel } from '../tab-panel'; -const filePath = './test-results/onIndexChange.txt'; +let tabIndex: number; const comp: any = ( - - writeFileSync(filePath, index.toString()) - }> + (tabIndex = index)}> Test 1 Test 2 @@ -44,9 +40,7 @@ const testComponent = () => { const testActions = () => { test('should be clickable', async ({ mount }) => { - if (existsSync(filePath)) { - rmSync(filePath); - } + expect(tabIndex).toBe(undefined); const component = await mount(comp); await component @@ -59,7 +53,7 @@ const testActions = () => { .isChecked(); expect(!tabChecked).toBeTruthy(); - expect(existsSync(filePath)).toBeTruthy(); + expect(tabIndex).toBe(1); }); }; From fb22490c7b31a55edac963f7aee9e6d6e4821545 Mon Sep 17 00:00:00 2001 From: Milan Wanielik Date: Thu, 30 Oct 2025 20:31:46 +0100 Subject: [PATCH 3/8] Fix DBTabItem selected state and aria-selected attribute Now also sets aria-selected=true|false correctly which improves screen reader behaviour. --- .changeset/sharp-pumas-obey.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/sharp-pumas-obey.md diff --git a/.changeset/sharp-pumas-obey.md b/.changeset/sharp-pumas-obey.md new file mode 100644 index 000000000000..f30b3da45ea2 --- /dev/null +++ b/.changeset/sharp-pumas-obey.md @@ -0,0 +1,6 @@ +--- +"@db-ux/core-components": patch +--- + +fix: set DBTabItem internal state `_selected` correctly +- now also sets aria-selected=true|false correctly which improves screen reader behaviour From 83dda9dcfe602aab515581c7342b9d4e01da197a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 30 Oct 2025 19:52:41 +0000 Subject: [PATCH 4/8] auto update snapshots (#5400) Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .../DBTabItem-should-have-same-aria-snapshot.yaml | 2 +- .../DBTabItem-should-have-same-aria-snapshot.yaml | 2 +- .../DBTabItem-should-have-same-aria-snapshot.yaml | 2 +- .../DBTabItem-should-have-same-aria-snapshot.yaml | 2 +- .../DBTabItem-should-have-same-aria-snapshot.yaml | 2 +- .../DBTabItem-should-have-same-aria-snapshot.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/__snapshots__/tab-item/showcase/chromium-highContrast/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml b/__snapshots__/tab-item/showcase/chromium-highContrast/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml index 14ee8a7543c6..41038b58c946 100644 --- a/__snapshots__/tab-item/showcase/chromium-highContrast/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml +++ b/__snapshots__/tab-item/showcase/chromium-highContrast/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml @@ -15,7 +15,7 @@ - tab "(Default) Enabled" - text: (Default) Enabled - tablist: - - tab "active" [selected] + - tab "active" - text: active - tablist: - tab "disabled" [disabled] diff --git a/__snapshots__/tab-item/showcase/chromium/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml b/__snapshots__/tab-item/showcase/chromium/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml index 14ee8a7543c6..41038b58c946 100644 --- a/__snapshots__/tab-item/showcase/chromium/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml +++ b/__snapshots__/tab-item/showcase/chromium/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml @@ -15,7 +15,7 @@ - tab "(Default) Enabled" - text: (Default) Enabled - tablist: - - tab "active" [selected] + - tab "active" - text: active - tablist: - tab "disabled" [disabled] diff --git a/__snapshots__/tab-item/showcase/firefox/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml b/__snapshots__/tab-item/showcase/firefox/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml index 14ee8a7543c6..41038b58c946 100644 --- a/__snapshots__/tab-item/showcase/firefox/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml +++ b/__snapshots__/tab-item/showcase/firefox/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml @@ -15,7 +15,7 @@ - tab "(Default) Enabled" - text: (Default) Enabled - tablist: - - tab "active" [selected] + - tab "active" - text: active - tablist: - tab "disabled" [disabled] diff --git a/__snapshots__/tab-item/showcase/mobile-chrome/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml b/__snapshots__/tab-item/showcase/mobile-chrome/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml index 14ee8a7543c6..41038b58c946 100644 --- a/__snapshots__/tab-item/showcase/mobile-chrome/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml +++ b/__snapshots__/tab-item/showcase/mobile-chrome/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml @@ -15,7 +15,7 @@ - tab "(Default) Enabled" - text: (Default) Enabled - tablist: - - tab "active" [selected] + - tab "active" - text: active - tablist: - tab "disabled" [disabled] diff --git a/__snapshots__/tab-item/showcase/mobile-safari/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml b/__snapshots__/tab-item/showcase/mobile-safari/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml index 14ee8a7543c6..41038b58c946 100644 --- a/__snapshots__/tab-item/showcase/mobile-safari/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml +++ b/__snapshots__/tab-item/showcase/mobile-safari/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml @@ -15,7 +15,7 @@ - tab "(Default) Enabled" - text: (Default) Enabled - tablist: - - tab "active" [selected] + - tab "active" - text: active - tablist: - tab "disabled" [disabled] diff --git a/__snapshots__/tab-item/showcase/webkit/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml b/__snapshots__/tab-item/showcase/webkit/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml index 14ee8a7543c6..41038b58c946 100644 --- a/__snapshots__/tab-item/showcase/webkit/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml +++ b/__snapshots__/tab-item/showcase/webkit/should-have-same-aria-snapshot/DBTabItem-should-have-same-aria-snapshot.yaml @@ -15,7 +15,7 @@ - tab "(Default) Enabled" - text: (Default) Enabled - tablist: - - tab "active" [selected] + - tab "active" - text: active - tablist: - tab "disabled" [disabled] From 91f9c90d63072a87655a97e67812f39fa9329270 Mon Sep 17 00:00:00 2001 From: Milan Wanielik Date: Mon, 3 Nov 2025 12:57:22 +0100 Subject: [PATCH 5/8] fix: pass correct tab item index from DBTab parent to child set child active after event registered, remove event listerner on unmount --- .../src/components/tab-item/tab-item.lite.tsx | 24 +++++++++++++------ .../src/components/tabs/tabs.lite.tsx | 4 ++-- .../src/components/tabs/tabs.spec.tsx | 3 +++ 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/components/src/components/tab-item/tab-item.lite.tsx b/packages/components/src/components/tab-item/tab-item.lite.tsx index 25869f00d11a..89f1af8f41a7 100644 --- a/packages/components/src/components/tab-item/tab-item.lite.tsx +++ b/packages/components/src/components/tab-item/tab-item.lite.tsx @@ -1,5 +1,6 @@ import { onMount, + onUnMount, onUpdate, Show, useDefaultProps, @@ -28,6 +29,10 @@ useDefaultProps({}); export default function DBTabItem(props: DBTabItemProps) { const _ref = useRef(null); + function setSelectedOnChange(event: any) { + state._selected = event.target === _ref; + } + // jscpd:ignore-start const state = useStore({ _selected: false, @@ -65,20 +70,18 @@ export default function DBTabItem(props: DBTabItemProps) { onUpdate(() => { if (state.initialized && _ref) { - if (props.active) { - _ref.click(); - } - useTarget({ react: () => state.handleNameAttribute() }); state.initialized = false; // deselect this tab when another tab in tablist is selected _ref.closest('[role=tablist]')?.addEventListener( 'change', - (event: any) => { - state._selected = event.target === _ref; - } + setSelectedOnChange ); + + if (props.active) { + _ref.click(); + } } }, [_ref, state.initialized]); @@ -88,6 +91,13 @@ export default function DBTabItem(props: DBTabItemProps) { } }, [props.name]); + onUnMount(() => { + _ref.closest('[role=tablist]')?.removeEventListener( + 'change', + setSelectedOnChange + ); + }); + return (