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 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..fc8917165a10 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, @@ -27,6 +28,18 @@ useDefaultProps({}); export default function DBTabItem(props: DBTabItemProps) { const _ref = useRef(null); + + function setSelectedOnChange(event: any) { + useTarget({ + stencil: () => { + state._selected = getBooleanAsString(event.target === _ref); + }, + default: () => { + state._selected = event.target === _ref; + } + }); + } + // jscpd:ignore-start const state = useStore({ _selected: false, @@ -49,17 +62,16 @@ 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']; - } - }); + if (_ref.checked && !state._selected) { + useTarget({ + stencil: () => { + state._selected = getBooleanAsString(true); + }, + default: () => { + state._selected = true; + } + }); + } useTarget({ angular: () => @@ -76,12 +88,26 @@ export default function DBTabItem(props: DBTabItemProps) { onUpdate(() => { if (state.initialized && _ref) { + useTarget({ react: () => state.handleNameAttribute() }); + state.initialized = false; + + // deselect this tab when another tab in tablist is selected + _ref.closest('[role=tablist]')?.addEventListener( + 'change', + setSelectedOnChange + ); + if (props.active) { + useTarget({ + stencil: () => { + state._selected = getBooleanAsString(true); + }, + default: () => { + state._selected = true; + } + }); _ref.click(); } - - useTarget({ react: () => state.handleNameAttribute() }); - state.initialized = false; } }, [_ref, state.initialized]); @@ -91,6 +117,15 @@ export default function DBTabItem(props: DBTabItemProps) { } }, [props.name]); + onUnMount(() => { + if (state.initialized && _ref) { + _ref.closest('[role=tablist]')?.removeEventListener( + 'change', + setSelectedOnChange + ); + } + }); + return (