Skip to content

Commit 2466780

Browse files
authored
fix(tabs): Internal DOM reference checks in observers (#1705)
Check for the existence of the tab header strip and indicator, if applicable, before trying to manipulate DOM state inside the observers callbacks.
1 parent 4dbd212 commit 2466780

File tree

2 files changed

+23
-6
lines changed

2 files changed

+23
-6
lines changed

src/components/tabs/tab-dom.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ class TabsHelpers {
2222
/**
2323
* Returns the DOM container holding the tabs headers.
2424
*/
25-
public get container(): HTMLElement {
26-
return this._container.value!;
25+
public get container(): HTMLElement | undefined {
26+
return this._container.value;
2727
}
2828

2929
/**
3030
* Returns the selected indicator DOM element.
3131
*/
32-
public get indicator(): HTMLElement {
33-
return this._indicator.value!;
32+
public get indicator(): HTMLElement | undefined {
33+
return this._indicator.value;
3434
}
3535

3636
/**
@@ -82,7 +82,9 @@ class TabsHelpers {
8282
public setStyleProperties(): void {
8383
this._styleProperties = {
8484
'--_tabs-count': this._host.tabs.length.toString(),
85-
'--_ig-tabs-width': `${this.container.getBoundingClientRect().width}px`,
85+
'--_ig-tabs-width': this.container
86+
? `${this.container.getBoundingClientRect().width}px`
87+
: '',
8688
};
8789
this._host.requestUpdate();
8890
}
@@ -91,13 +93,19 @@ class TabsHelpers {
9193
* Sets the type of the `scroll-snap-align` CSS property for the tabs header strip.
9294
*/
9395
public setScrollSnap(type?: 'start' | 'end'): void {
94-
this.container.style.setProperty('--_ig-tab-snap', type || 'unset');
96+
if (this.container) {
97+
this.container.style.setProperty('--_ig-tab-snap', type || 'unset');
98+
}
9599
}
96100

97101
/**
98102
* Scrolls the tabs header strip in the given direction with `scroll-snap-align` set.
99103
*/
100104
public scrollTabs(direction: 'start' | 'end'): void {
105+
if (!this.container) {
106+
return;
107+
}
108+
101109
const factor = isLTR(this._host) ? 1 : -1;
102110
const amount =
103111
direction === 'start'
@@ -113,6 +121,10 @@ class TabsHelpers {
113121
* Triggers an update cycle (rerender) of the `igc-tabs` component.
114122
*/
115123
public setScrollButtonState(): void {
124+
if (!this.container) {
125+
return;
126+
}
127+
116128
const { scrollLeft, scrollWidth, clientWidth } = this.container;
117129

118130
this._hasScrollButtons = scrollWidth > clientWidth;
@@ -128,6 +140,10 @@ class TabsHelpers {
128140
* Updates the indicator DOM element styles based on the current "active" tab.
129141
*/
130142
public async setIndicator(active?: IgcTabComponent): Promise<void> {
143+
if (!(this.container && this.indicator)) {
144+
return;
145+
}
146+
131147
const styles = {
132148
visibility: active ? 'visible' : 'hidden',
133149
} satisfies Partial<CSSStyleDeclaration>;

src/components/tabs/tabs.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,7 @@ describe('Tabs component', () => {
631631

632632
describe('issue-1140', () => {
633633
it('Tabs throw if a child tab is immediately appended', async () => {
634+
// https://github.com/IgniteUI/igniteui-webcomponents/pull/1705#issuecomment-2912189331
634635
const tabs = document.createElement(IgcTabsComponent.tagName);
635636
const tab = document.createElement(IgcTabComponent.tagName);
636637
document.body.appendChild(tabs);

0 commit comments

Comments
 (0)