diff --git a/src/elements/tabs/tab-group/__snapshots__/tab-group.snapshot.spec.snap.js b/src/elements/tabs/tab-group/__snapshots__/tab-group.snapshot.spec.snap.js
index a3f060ddf0..94d0462b14 100644
--- a/src/elements/tabs/tab-group/__snapshots__/tab-group.snapshot.spec.snap.js
+++ b/src/elements/tabs/tab-group/__snapshots__/tab-group.snapshot.spec.snap.js
@@ -21,9 +21,7 @@ snapshots["sbb-tab-group renders DOM"] =
role="tabpanel"
tabindex="0"
>
-
- Test tab content 1
-
+ Test tab content 1
-
- Test tab content 2
-
+ Test tab content 2
-
- Test tab content 3
-
+ Test tab content 3
-
- Test tab content 4
-
+ Test tab content 4
`;
@@ -173,7 +165,7 @@ snapshots["sbb-tab-group renders A11y tree Firefox"] =
"children": [
{
"role": "text leaf",
- "name": "Test tab content 1"
+ "name": "Test tab content 1 "
}
]
}
diff --git a/src/elements/tabs/tab-group/readme.md b/src/elements/tabs/tab-group/readme.md
index 28fa042ceb..5dba0c1b67 100644
--- a/src/elements/tabs/tab-group/readme.md
+++ b/src/elements/tabs/tab-group/readme.md
@@ -8,19 +8,13 @@ tab panels can present different sections of content and include text, images, f
```html
I am the first
-
- Tab content 1
-
+ Tab content 1
I am the second
-
- Tab content 2
-
+ Tab content 2
I am the third
-
- Tab content 3
-
+ Tab content 3
```
@@ -28,7 +22,7 @@ To display a tab label within the tab bar, provide a `sbb-tab-label` right befor
please refer to the [sbb-tab-label](/docs/elements-sbb-tab-sbb-tab-label--docs) documentation for more details.
The content element must be wrapped in a `sbb-tab` and placed right after its relative `sbb-tab-label`.
-Tab groups can also be nested, which means that a tab's content block can be represented by another `sbb-tab-group`,
+Tab groups can also be nested, which means that a `sbb-tab` can contain another `sbb-tab-group`,
as shown in the "Nested Tab Groups" example.
## States
@@ -84,7 +78,6 @@ type SbbTabChangedEventDetails = {
## Slots
-| Name | Description |
-| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
-| | Use the unnamed slot to add html-content to the `sbb-tab-group`; wrap the content in a `sbb-tab` or provide a nested `sbb-tab-group`. |
-| `tab-bar` | When you provide the `sbb-tab-label` tag through the unnamed slot, it will be automatically moved to this slot. You do not need to use it directly. |
+| Name | Description |
+| ---- | ------------------------------------------------------------------------------------------------------- |
+| | Use the unnamed slot to add content to the `sbb-tab-group` via `sbb-tab-label` and `sbb-tab` instances. |
diff --git a/src/elements/tabs/tab-group/tab-group.scss b/src/elements/tabs/tab-group/tab-group.scss
index 1e441f7808..c24d038fb2 100644
--- a/src/elements/tabs/tab-group/tab-group.scss
+++ b/src/elements/tabs/tab-group/tab-group.scss
@@ -51,11 +51,3 @@
@include sbb.focus-outline;
}
}
-
-// Make inactive nested tab groups non-focusable, to ensure accessibility
-:host([data-nested]:not([active])) *,
-:host([data-nested]:not([active])) ::slotted(*) {
- visibility: hidden;
- opacity: 0;
- height: 0;
-}
diff --git a/src/elements/tabs/tab-group/tab-group.snapshot.spec.ts b/src/elements/tabs/tab-group/tab-group.snapshot.spec.ts
index c8a06dc0e9..01347f02b8 100644
--- a/src/elements/tabs/tab-group/tab-group.snapshot.spec.ts
+++ b/src/elements/tabs/tab-group/tab-group.snapshot.spec.ts
@@ -16,21 +16,13 @@ describe(`sbb-tab-group`, () => {
element = await fixture(
html`
Test tab label 1
-
- Test tab content 1
-
+ Test tab content 1
Test tab label 2
-
- Test tab content 2
-
+ Test tab content 2
Test tab label 3
-
- Test tab content 3
-
+ Test tab content 3
Test tab label 4
-
- Test tab content 4
-
+ Test tab content 4
`,
);
});
diff --git a/src/elements/tabs/tab-group/tab-group.spec.ts b/src/elements/tabs/tab-group/tab-group.spec.ts
index 06040da093..95f0d95efe 100644
--- a/src/elements/tabs/tab-group/tab-group.spec.ts
+++ b/src/elements/tabs/tab-group/tab-group.spec.ts
@@ -20,13 +20,13 @@ describe(`sbb-tab-group`, () => {
element = await fixture(
html`
Test tab label 1
- Test tab content 1
+ Test tab content 1
Test tab label 2
- Test tab content 2
+ Test tab content 2
Test tab label 3
- Test tab content 3
+ Test tab content 3
Test tab label 4
- Test tab content 4
+ Test tab content 4
`,
);
});
@@ -153,13 +153,9 @@ describe(`sbb-tab-group`, () => {
element = await fixture(
html`
Test tab label 1
-
- Test tab content 1
-
+ Test tab content 1
Test tab label 2
-
- Test tab content 2
-
+ Test tab content 2
`,
);
const tab = element.querySelector('sbb-tab-label#sbb-tab-1');
@@ -170,13 +166,9 @@ describe(`sbb-tab-group`, () => {
element = await fixture(
html`
Test tab label 1
-
- Test tab content 1
-
+ Test tab content 1
Test tab label 2
-
- Test tab content 2
-
+ Test tab content 2
`,
);
const tab = element.querySelector('sbb-tab-label#sbb-tab-2');
diff --git a/src/elements/tabs/tab-group/tab-group.ssr.spec.ts b/src/elements/tabs/tab-group/tab-group.ssr.spec.ts
index b8c2d29179..0916ec826a 100644
--- a/src/elements/tabs/tab-group/tab-group.ssr.spec.ts
+++ b/src/elements/tabs/tab-group/tab-group.ssr.spec.ts
@@ -14,21 +14,13 @@ describe(`sbb-tab-group ssr`, () => {
root = await ssrHydratedFixture(
html`
Test tab label 1
-
- Test tab content 1
-
+ Test tab content 1
Test tab label 2
-
- Test tab content 2
-
+ Test tab content 2
Test tab label 3
-
- Test tab content 3
-
+ Test tab content 3
Test tab label 4
-
- Test tab content 4
-
+ Test tab content 4
`,
{ modules: ['./tab-group.js', '../tab-label.js', '../tab.js'] },
);
diff --git a/src/elements/tabs/tab-group/tab-group.stories.ts b/src/elements/tabs/tab-group/tab-group.stories.ts
index 7dbd2edfb6..c62025a5e5 100644
--- a/src/elements/tabs/tab-group/tab-group.stories.ts
+++ b/src/elements/tabs/tab-group/tab-group.stories.ts
@@ -63,12 +63,10 @@ const tabPanelTwo = (): TemplateResult => html`
const tabPanelFour = (): TemplateResult => html`
-
- Diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod
- elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus
- urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus
- turpis in eu mi bibendum neque egestas congue.
-
+ Diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod
+ elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis rhoncus
+ urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed faucibus
+ turpis in eu mi bibendum neque egestas congue.
`;
@@ -116,26 +114,24 @@ const IconsAndNumbersTemplate = ({ size, label, ...args }: Args): TemplateResult
const NestedTemplate = ({ size, label, ...args }: Args): TemplateResult => html`
${firstTabTitle(label, args)}
-
- Nested tab
-
-
+
+
+ Nested tab
+
Diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod
elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis
rhoncus urna neque viverra justo nec ultrices dui sapien eget mi proin sed libero enim sed
faucibus turpis in eu mi bibendum neque egestas congue.
-
-
+
- Nested tab
-
-
+ Nested tab
+
Diam maecenas ultricies mi eget mauris pharetra et ultrices neque ornare aenean euismod
elementum nisi quis eleifend quam adipiscing vitae proin sagittis nisl rhoncus mattis
rhoncus urna.
-
-
-
+
+
+
Tab title two
${tabPanelTwo()}
@@ -143,7 +139,7 @@ const NestedTemplate = ({ size, label, ...args }: Args): TemplateResult => html`
Tab title three
- I was disabled.
+ I was disabled.
Tab title four
${tabPanelFour()}
diff --git a/src/elements/tabs/tab-group/tab-group.ts b/src/elements/tabs/tab-group/tab-group.ts
index abf67f5f97..f277034c6c 100644
--- a/src/elements/tabs/tab-group/tab-group.ts
+++ b/src/elements/tabs/tab-group/tab-group.ts
@@ -12,8 +12,6 @@ import { SbbTabElement } from '../tab.js';
import style from './tab-group.scss?lit&inline';
-export type SbbTabSupportedContentType = SbbTabElement | SbbTabGroupElement;
-
export type SbbTabChangedEventDetails = {
activeIndex: number;
activeTabLabel: SbbTabLabelElement;
@@ -34,7 +32,7 @@ export interface InterfaceSbbTabGroupActions {
export interface InterfaceSbbTabGroupTab extends SbbTabLabelElement {
active?: boolean;
disabled: boolean;
- relatedContent?: SbbTabSupportedContentType;
+ tab?: SbbTabElement;
index?: number;
tabGroupActions?: InterfaceSbbTabGroupActions;
size: 's' | 'l' | 'xl';
@@ -44,17 +42,13 @@ const tabObserverConfig: MutationObserverInit = {
attributeFilter: ['active', 'disabled'],
};
-const SUPPORTED_CONTENT_WRAPPERS = ['sbb-tab', 'sbb-tab-group'];
-
let nextId = 0;
/**
- * It displays one or more tab, each one with a title and a content.
+ * It displays one or more tabs, each one with a label and a content.
*
- * @slot - Use the unnamed slot to add html-content to the `sbb-tab-group`;
- * wrap the content in a `sbb-tab` or provide a nested `sbb-tab-group`.
- * @slot tab-bar - When you provide the `sbb-tab-label` tag through the unnamed slot,
- * it will be automatically moved to this slot. You do not need to use it directly.
+ * @slot - Use the unnamed slot to add content to the `sbb-tab-group` via
+ * `sbb-tab-label` and `sbb-tab` instances.
* @event {CustomEvent} didChange - Emits an event on selected tab change.
*/
@customElement('sbb-tab-group')
@@ -146,7 +140,6 @@ export class SbbTabGroupElement extends LitElement {
super.connectedCallback();
const signal = this._abort.signal;
this.addEventListener('keydown', (e) => this._handleKeyDown(e), { signal });
- this.toggleAttribute('data-nested', !!this.parentElement?.closest('sbb-tab-group'));
}
protected override firstUpdated(changedProperties: PropertyValues): void {
@@ -184,7 +177,7 @@ export class SbbTabGroupElement extends LitElement {
const removedTabs = this._tabs.filter((tab) => !tabs.includes(tab));
removedTabs.forEach((removedTab) => {
- removedTab.relatedContent?.remove();
+ removedTab.tab?.remove();
});
this._tabs = tabs;
}
@@ -255,105 +248,102 @@ export class SbbTabGroupElement extends LitElement {
}
}
- private _configure(tab: InterfaceSbbTabGroupTab): void {
- tab.tabGroupActions = {
+ private _configure(tabLabel: InterfaceSbbTabGroupTab): void {
+ tabLabel.tabGroupActions = {
activate: (): void => {
- tab.toggleAttribute('active', true);
- tab.active = true;
- tab.tabIndex = 0;
- tab.setAttribute('aria-selected', 'true');
- tab.relatedContent?.toggleAttribute('active', true);
+ tabLabel.toggleAttribute('active', true);
+ tabLabel.active = true;
+ tabLabel.tabIndex = 0;
+ tabLabel.setAttribute('aria-selected', 'true');
+ tabLabel.tab?.toggleAttribute('active', true);
},
deactivate: (): void => {
- tab.removeAttribute('active');
- tab.active = false;
- tab.tabIndex = -1;
- tab.setAttribute('aria-selected', 'false');
- tab.relatedContent?.removeAttribute('active');
+ tabLabel.removeAttribute('active');
+ tabLabel.active = false;
+ tabLabel.tabIndex = -1;
+ tabLabel.setAttribute('aria-selected', 'false');
+ tabLabel.tab?.removeAttribute('active');
},
disable: (): void => {
- if (tab.disabled) {
+ if (tabLabel.disabled) {
return;
}
- if (!tab.hasAttribute('disabled')) {
- tab.toggleAttribute('disabled', true);
+ if (!tabLabel.hasAttribute('disabled')) {
+ tabLabel.toggleAttribute('disabled', true);
}
- tab.disabled = true;
- tab.tabIndex = -1;
- tab.setAttribute('aria-selected', 'false');
- tab.relatedContent?.removeAttribute('active');
- if (tab.active) {
- tab.removeAttribute('active');
- tab.active = false;
+ tabLabel.disabled = true;
+ tabLabel.tabIndex = -1;
+ tabLabel.setAttribute('aria-selected', 'false');
+ tabLabel.tab?.removeAttribute('active');
+ if (tabLabel.active) {
+ tabLabel.removeAttribute('active');
+ tabLabel.active = false;
this._enabledTabs[0]?.tabGroupActions?.select();
}
},
enable: (): void => {
- if (tab.disabled) {
- tab.removeAttribute('disabled');
- tab.disabled = false;
+ if (tabLabel.disabled) {
+ tabLabel.removeAttribute('disabled');
+ tabLabel.disabled = false;
}
},
select: (): void => {
- if (tab !== this._selectedTab && !tab.disabled) {
+ if (tabLabel !== this._selectedTab && !tabLabel.disabled) {
const prevTab = this._selectedTab;
if (prevTab) {
prevTab.tabGroupActions?.deactivate();
- this._tabContentResizeObserver.unobserve(prevTab.relatedContent!);
+ this._tabContentResizeObserver.unobserve(prevTab.tab!);
}
- tab.tabGroupActions?.activate();
- this._selectedTab = tab;
+ tabLabel.tabGroupActions?.activate();
+ this._selectedTab = tabLabel;
- this._tabContentResizeObserver.observe(tab.relatedContent!);
+ this._tabContentResizeObserver.observe(tabLabel.tab!);
const tabs = this._tabs;
this._selectedTabChanged.emit({
- activeIndex: tabs.findIndex((e) => e === tab),
- activeTabLabel: tab,
- activeTab: tab.relatedContent as SbbTabElement,
+ activeIndex: tabs.findIndex((e) => e === tabLabel),
+ activeTabLabel: tabLabel,
+ activeTab: tabLabel.tab as SbbTabElement,
previousIndex: tabs.findIndex((e) => e === prevTab),
previousTabLabel: prevTab,
- previousTab: prevTab?.relatedContent as SbbTabElement,
+ previousTab: prevTab?.tab as SbbTabElement,
});
- } else if (import.meta.env.DEV && tab.disabled) {
+ } else if (import.meta.env.DEV && tabLabel.disabled) {
console.warn('You cannot activate a disabled tab');
}
},
};
- if (
- tab.nextElementSibling?.localName &&
- SUPPORTED_CONTENT_WRAPPERS.includes(tab.nextElementSibling?.localName)
- ) {
- tab.relatedContent = tab.nextElementSibling as SbbTabSupportedContentType;
- tab.relatedContent.id = this._assignId();
- if (tab.relatedContent instanceof SbbTabElement) {
- tab.relatedContent.tabIndex = 0;
- tab.relatedContent.configure();
+ if (tabLabel.nextElementSibling?.localName === 'sbb-tab') {
+ tabLabel.tab = tabLabel.nextElementSibling as SbbTabElement;
+ tabLabel.tab.id = this._assignId();
+ if (tabLabel.tab instanceof SbbTabElement) {
+ tabLabel.tab.tabIndex = 0;
+ tabLabel.tab.configure();
}
} else if (import.meta.env.DEV) {
- tab.insertAdjacentHTML('afterend', 'No content.');
- tab.relatedContent = tab.nextElementSibling as SbbTabSupportedContentType;
+ tabLabel.insertAdjacentHTML('afterend', 'No content.');
+ tabLabel.tab = tabLabel.nextElementSibling as SbbTabElement;
console.warn(
- `Missing content: you should provide a related content for the tab ${tab.outerHTML}.`,
+ `Missing content: you should provide a related content for the tab ${tabLabel.outerHTML}.`,
);
}
- tab.tabIndex = -1;
- tab.disabled = tab.hasAttribute('disabled');
- tab.active = tab.hasAttribute('active') && !tab.disabled;
- tab.setAttribute('role', 'tab');
- tab.setAttribute('aria-selected', 'false');
- tab.addEventListener('click', () => {
- tab.tabGroupActions?.select();
+ tabLabel.tabIndex = -1;
+ tabLabel.disabled = tabLabel.hasAttribute('disabled');
+ tabLabel.active = tabLabel.hasAttribute('active') && !tabLabel.disabled;
+ tabLabel.setAttribute('role', 'tab');
+ tabLabel.setAttribute('aria-selected', 'false');
+ tabLabel.addEventListener('click', () => {
+ tabLabel.tabGroupActions?.select();
});
- if (tab.relatedContent) {
- tab.setAttribute('aria-controls', tab.relatedContent.id);
- tab.relatedContent.setAttribute('role', 'tabpanel');
- tab.relatedContent.toggleAttribute('active', tab.active);
+ if (tabLabel.tab) {
+ tabLabel.setAttribute('aria-controls', tabLabel.tab.id);
+ tabLabel.tab.setAttribute('role', 'tabpanel');
+ tabLabel.tab.toggleAttribute('active', tabLabel.active);
}
- this._tabAttributeObserver.observe(tab, tabObserverConfig);
- tab.slot = 'tab-bar';
+ this._tabAttributeObserver.observe(tabLabel, tabObserverConfig);
+ tabLabel.slot = 'tab-bar';
}
private _handleKeyDown(evt: KeyboardEvent): void {
diff --git a/src/elements/tabs/tab/__snapshots__/tab.snapshot.spec.snap.js b/src/elements/tabs/tab/__snapshots__/tab.snapshot.spec.snap.js
index c804684db4..58fa09e99a 100644
--- a/src/elements/tabs/tab/__snapshots__/tab.snapshot.spec.snap.js
+++ b/src/elements/tabs/tab/__snapshots__/tab.snapshot.spec.snap.js
@@ -3,9 +3,7 @@ export const snapshots = {};
snapshots["sbb-tab renders DOM"] =
`
-
- Content
-
+ Content
`;
/* end snapshot sbb-tab renders DOM */
diff --git a/src/elements/tabs/tab/readme.md b/src/elements/tabs/tab/readme.md
index f6f43bca7c..c52d5e2501 100644
--- a/src/elements/tabs/tab/readme.md
+++ b/src/elements/tabs/tab/readme.md
@@ -2,9 +2,7 @@ The `sbb-tab` is a component used to provide content to a `sbb-tab-group`
(see [sbb-tab-group](/docs/elements-sbb-tab-sbb-tab-group--docs) for more details).
```html
-
- Content
-
+ Content
```
## Slots
diff --git a/src/elements/tabs/tab/tab.snapshot.spec.ts b/src/elements/tabs/tab/tab.snapshot.spec.ts
index d6f5025799..4a0b1fd572 100644
--- a/src/elements/tabs/tab/tab.snapshot.spec.ts
+++ b/src/elements/tabs/tab/tab.snapshot.spec.ts
@@ -11,7 +11,7 @@ describe(`sbb-tab`, () => {
let element: SbbTabElement;
beforeEach(async () => {
- element = await fixture(html`Content
`);
+ element = await fixture(html`Content`);
});
it('DOM', async () => {
diff --git a/src/elements/tabs/tab/tab.spec.ts b/src/elements/tabs/tab/tab.spec.ts
index 292c332d59..9e2d033198 100644
--- a/src/elements/tabs/tab/tab.spec.ts
+++ b/src/elements/tabs/tab/tab.spec.ts
@@ -9,7 +9,7 @@ describe('sbb-tab', () => {
let element: SbbTabElement;
beforeEach(async () => {
- element = await fixture(html`Content
`);
+ element = await fixture(html`Content`);
});
it('renders', async () => {
diff --git a/src/elements/tabs/tab/tab.ssr.spec.ts b/src/elements/tabs/tab/tab.ssr.spec.ts
index ff0ea8c23e..3357a0dce9 100644
--- a/src/elements/tabs/tab/tab.ssr.spec.ts
+++ b/src/elements/tabs/tab/tab.ssr.spec.ts
@@ -9,7 +9,7 @@ describe(`sbb-tab ssr`, () => {
let root: SbbTabElement;
beforeEach(async () => {
- root = await ssrHydratedFixture(html`Content
`, {
+ root = await ssrHydratedFixture(html`Content`, {
modules: ['./tab.js'],
});
});
diff --git a/src/elements/tabs/tab/tab.stories.ts b/src/elements/tabs/tab/tab.stories.ts
index 3279e3f861..6e5dcf31da 100644
--- a/src/elements/tabs/tab/tab.stories.ts
+++ b/src/elements/tabs/tab/tab.stories.ts
@@ -5,11 +5,7 @@ import { html } from 'lit';
import readme from './readme.md?raw';
import './tab.js';
-const Template = (): TemplateResult => html`
-
- Content
-
-`;
+const Template = (): TemplateResult => html` Content `;
export const Default: StoryObj = {
render: Template,