diff --git a/docs/pages/resources/changelog.md b/docs/pages/resources/changelog.md index e4dab556..a6e70970 100644 --- a/docs/pages/resources/changelog.md +++ b/docs/pages/resources/changelog.md @@ -12,6 +12,10 @@ Components with the Experimental bad New versions of Shoelace are released as-needed and generally occur when a critical mass of changes have accumulated. At any time, you can see what's coming in the next release by visiting [next.shoelace.style](https://next.shoelace.style). +## next + +- Fixed a bug that prevented `` to be activated properly when rendered in another `` (#2367) + ## 2.20.0 - Added the ability to set a custom snap function and use `repeat(n)` to `` [#2340] diff --git a/src/components/tab-group/tab-group.component.ts b/src/components/tab-group/tab-group.component.ts index 5e7064fd..8a9de2bc 100644 --- a/src/components/tab-group/tab-group.component.ts +++ b/src/components/tab-group/tab-group.component.ts @@ -93,17 +93,33 @@ export default class SlTabGroup extends ShoelaceElement { }); this.mutationObserver = new MutationObserver(mutations => { + // Make sure to only observe the direct children of the tab group + // instead of other sub elements that might be slotted in. + // @see https://github.com/shoelace-style/shoelace/issues/2320 + const instanceMutations = mutations.filter(({ target }) => { + if (target === this) return true; // Allow self updates + if ((target as HTMLElement).closest('sl-tab-group') !== this) return false; // We are not direct children + + // We should only care about changes to the tab or tab panel + const tagName = (target as HTMLElement).tagName.toLowerCase(); + return tagName === 'sl-tab' || tagName === 'sl-tab-panel'; + }); + + if (instanceMutations.length === 0) { + return; + } + // Update aria labels when the DOM changes - if (mutations.some(m => !['aria-labelledby', 'aria-controls'].includes(m.attributeName!))) { + if (instanceMutations.some(m => !['aria-labelledby', 'aria-controls'].includes(m.attributeName!))) { setTimeout(() => this.setAriaLabels()); } // Sync tabs when disabled states change - if (mutations.some(m => m.attributeName === 'disabled')) { + if (instanceMutations.some(m => m.attributeName === 'disabled')) { this.syncTabsAndPanels(); // sync tabs when active state on tab changes - } else if (mutations.some(m => m.attributeName === 'active')) { - const tabs = mutations + } else if (instanceMutations.some(m => m.attributeName === 'active')) { + const tabs = instanceMutations .filter(m => m.attributeName === 'active' && (m.target as HTMLElement).tagName.toLowerCase() === 'sl-tab') .map(m => m.target as SlTab); const newActiveTab = tabs.find(tab => tab.active); @@ -117,7 +133,14 @@ export default class SlTabGroup extends ShoelaceElement { // After the first update... this.updateComplete.then(() => { this.syncTabsAndPanels(); - this.mutationObserver.observe(this, { attributes: true, childList: true, subtree: true }); + + this.mutationObserver.observe(this, { + attributes: true, + attributeFilter: ['active', 'disabled', 'name', 'panel'], + childList: true, + subtree: true + }); + this.resizeObserver.observe(this.nav); // Wait for tabs and tab panels to be registered