Skip to content

Commit 2f027ab

Browse files
authored
feat(Tab): implement full width attribute [run-chromatic][skip-cd] (#740)
2 parents 117f6d1 + f0e99a6 commit 2f027ab

8 files changed

Lines changed: 67 additions & 5 deletions

File tree

skills/sgds-components/reference/tab.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ No CSS styling modifications — custom properties and CSS parts are not exposed
2929
- `variant` controls visual style: `underlined` (default) or `solid`. Set on `<sgds-tab-group>` — propagates to all child tabs.
3030
- `orientation` controls layout: `horizontal` (default) or `vertical`. Set on `<sgds-tab-group>`.
3131
- `density` controls spacing: `default` or `compact`. Set on `<sgds-tab-group>`.
32+
- `fullWidth` on `<sgds-tab-group>` will stretch tab group to fill the whole width of its container. Only works if `orientation` is set to `horizontal`.
3233
- Fires `sgds-tab-show` (with `event.detail.name`) when a tab is activated and `sgds-tab-hide` when it is deactivated.
3334
- No public methods on `<sgds-tab-group>`.
3435

@@ -50,7 +51,7 @@ No CSS styling modifications — custom properties and CSS parts are not exposed
5051

5152
- **`panel`/`name` matching**: the link between a tab and its panel is entirely string-based — a typo in either attribute results in a broken tab with no panel displayed. Always verify both values match exactly.
5253
- **`active` attribute**: sets the initially active tab at render time only; once the tab group is interactive, active state is managed internally and the `active` attribute is not reactively updated.
53-
- **`variant` and `density` propagation**: these are set on `<sgds-tab-group>` and automatically propagate to all child `<sgds-tab>` elements — do not set them on individual tabs.
54+
- **`variant`, `orientation`, `density`, and `fullWidth` propagation**: these are set on `<sgds-tab-group>` and automatically propagate to all child `<sgds-tab>` elements — do not set them on individual tabs.
5455
- **`sgds-tab-show` / `sgds-tab-hide`**: both events fire with `event.detail.name` (the panel name string) — use to lazy-load content, track analytics, or sync URL state with the active tab.
5556
- **No public methods**: programmatic tab activation is not supported via methods — manage active state by adding/removing the `active` attribute on a `<sgds-tab>` directly if needed.
5657

@@ -74,6 +75,8 @@ No CSS styling modifications — custom properties and CSS parts are not exposed
7475

7576
**Compact spacing?**`density="compact"` on `<sgds-tab-group>`
7677

78+
**Stretch to fill whole width of container?**`fullWidth` on `<sgds-tab-group>`
79+
7780
**Set initial active tab?** → Add `active` to the specific `<sgds-tab>`
7881

7982
**Set initial active tab (first loaded tab)?** → The first non-disabled tab is active by default
@@ -112,6 +115,14 @@ No CSS styling modifications — custom properties and CSS parts are not exposed
112115
<sgds-tab-panel name="section2">Section 2 content.</sgds-tab-panel>
113116
</sgds-tab-group>
114117

118+
<!-- Full width -->
119+
<sgds-tab-group fullWidth>
120+
<sgds-tab slot="nav" panel="tab1" ariaLabel="Section 1">Tab 1</sgds-tab>
121+
<sgds-tab slot="nav" panel="tab2" ariaLabel="Section 2">Tab 2</sgds-tab>
122+
<sgds-tab-panel name="tab1">Tab 1 content.</sgds-tab-panel>
123+
<sgds-tab-panel name="tab2">Tab 2 content.</sgds-tab-panel>
124+
</sgds-tab-group>
125+
115126
<!-- Listen to tab change -->
116127
<sgds-tab-group id="my-tabs">
117128
<sgds-tab slot="nav" panel="a" ariaLabel="Tab A">Tab A</sgds-tab>
@@ -136,6 +147,7 @@ No CSS styling modifications — custom properties and CSS parts are not exposed
136147
| `variant` | `underlined \| solid` | `underlined` | Visual style of the tab list |
137148
| `orientation` | `horizontal \| vertical` | `horizontal` | Layout direction of the tabs |
138149
| `density` | `default \| compact` | `default` | Spacing of the tab items |
150+
| `fullWidth` | boolean | `false` | Sets whether tab group stretches to fill the whole width of its container. Only works if when `orientation` is set to `horizontal` |
139151

140152
### `<sgds-tab>`
141153

@@ -173,7 +185,7 @@ No CSS styling modifications — custom properties and CSS parts are not exposed
173185
**For AI agents**:
174186
1. `<sgds-tab>` must have `slot="nav"` and its `panel` must exactly match a `<sgds-tab-panel>`'s `name`.
175187
2. **Always add `ariaLabel`** to every `<sgds-tab>` — this is required for accessibility. The value should describe the tab's purpose (usually matches the visible label text).
176-
3. `variant`, `orientation`, and `density` are set on `<sgds-tab-group>` — they propagate automatically to all child `<sgds-tab>` elements.
188+
3. `variant`, `orientation`, `density`, and `fullWidth` are set on `<sgds-tab-group>` — they propagate automatically to all child `<sgds-tab>` elements.
177189
4. `sgds-tab-show` and `sgds-tab-hide` both carry `event.detail.name` which is the panel name string.
178190
5. To set the initially active tab, add `active` to one `<sgds-tab>` — if none are active, the first non-disabled tab is selected.
179191
6. There are no public methods on the tab group.

src/components/Tab/sgds-tab-group.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ export class SgdsTabGroup extends SgdsElement {
3939
@property({ type: String, reflect: true }) orientation: "horizontal" | "vertical" = "horizontal";
4040
/** The density of tabs. Controls the density of all `sgds-tabs` in its slot. It also sets the density attribute of `sgds-tab` */
4141
@property({ type: String, reflect: true }) density: "compact" | "default" = "default";
42+
/** When set, all `sgds-tabs` in its slot will be in full width. Only takes effect when `orientation` is set to `horizontal` */
43+
@property({ type: Boolean, reflect: true }) fullWidth = false;
4244

4345
connectedCallback() {
4446
const whenAllDefined = Promise.all([
@@ -235,6 +237,7 @@ export class SgdsTabGroup extends SgdsElement {
235237
this._updateTabsAttribute("variant");
236238
this._updateTabsAttribute("orientation");
237239
this._updateTabsAttribute("density");
240+
this._updateTabsAttribute("fullWidth");
238241
this._syncTabsAndPanels();
239242
}
240243

@@ -249,6 +252,9 @@ export class SgdsTabGroup extends SgdsElement {
249252
if (_changedProperties.has("density")) {
250253
this._updateTabsAttribute("density");
251254
}
255+
if (_changedProperties.has("fullWidth")) {
256+
this._updateTabsAttribute("fullWidth");
257+
}
252258
}
253259

254260
render() {

src/components/Tab/tab-group.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,7 @@
3434
:host([variant="underlined"][orientation="vertical"]) .tab-group__nav {
3535
border-right: var(--sgds-border-width-1) solid var(--sgds-border-color-muted);
3636
}
37+
38+
:host([fullWidth][orientation="horizontal"]) slot[name="nav"]::slotted(sgds-tab) {
39+
width: 100%;
40+
}

src/components/Tab/tab.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@
7575
background-color: var(--sgds-bg-translucent-subtle);
7676
}
7777

78+
:host([fullWidth][orientation="horizontal"]) .tab {
79+
justify-content: center;
80+
}
81+
7882
.tab {
7983
display: flex;
8084
align-items: center;

stories/component-templates/Tab/additional.mdx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,22 @@ By default, tabs are presented horizontally. Set `orientation` to `vertical` for
4949
<Story of={TabStories.OrientationSolid} />
5050
</Canvas>
5151

52+
## Full Width
53+
54+
Tabs can be set to fill the full width of its container by setting the `fullWidth` attribute to `true`. The `fullWidth` attribute only takes effect if the `orientation` attribute is also set to `horizontal`.
55+
56+
### Underlined tabs (default)
57+
58+
<Canvas of={TabStories.UnderlinedFullWidth}>
59+
<Story of={TabStories.UnderlinedFullWidth} />
60+
</Canvas>
61+
62+
### Solid tabs
63+
64+
<Canvas of={TabStories.SolidFullWidth}>
65+
<Story of={TabStories.SolidFullWidth} />
66+
</Canvas>
67+
5268
## Tab events
5369

5470
The `sgds-tab-group` component emits custom events when tabs are shown or hidden, allowing you to perform side effects and track which tab is currently active.

stories/component-templates/Tab/additional.stories.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,20 @@ export const SolidVariant = {
66
args: { variant: "solid" },
77
parameters: {}
88
};
9+
export const UnderlinedFullWidth = {
10+
render: Template.bind({}),
11+
name: "Full width underlined tabs",
12+
args: { fullWidth: true },
13+
parameters: {},
14+
tags: ["!dev"]
15+
};
16+
export const SolidFullWidth = {
17+
render: Template.bind({}),
18+
name: "Full width solid tabs",
19+
args: { variant: "solid", fullWidth: true },
20+
parameters: {},
21+
tags: ["!dev"]
22+
};
923
export const UnderlinedDensityCompact = {
1024
render: Template.bind({}),
1125
name: "Compact density for underlined tabs",

stories/component-templates/Tab/basic.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
import { html } from "lit";
22
import { ifDefined } from "lit/directives/if-defined.js";
33

4-
export const Template = ({ variant, orientation, density }) => html`
5-
<sgds-tab-group variant=${ifDefined(variant)} orientation=${ifDefined(orientation)} density=${ifDefined(density)}>
4+
export const Template = ({ variant, orientation, density, fullWidth }) => html`
5+
<sgds-tab-group
6+
variant=${ifDefined(variant)}
7+
orientation=${ifDefined(orientation)}
8+
density=${ifDefined(density)}
9+
?fullWidth=${fullWidth}
10+
>
611
<sgds-tab slot="nav" panel="home" ariaLabel="Home">Home</sgds-tab>
712
<sgds-tab slot="nav" panel="profile" ariaLabel="Profile">Profile</sgds-tab>
813
<sgds-tab slot="nav" panel="contact" ariaLabel="Contact">Contact</sgds-tab>

test/tab.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,8 @@ describe("<sgds-tab-group>", () => {
160160
const propsToForwardToChild = [
161161
{ name: "variant", defaultValue: "underlined", changedValue: "solid" },
162162
{ name: "density", defaultValue: "default", changedValue: "compact" },
163-
{ name: "orientation", defaultValue: "horizontal", changedValue: "vertical" }
163+
{ name: "orientation", defaultValue: "horizontal", changedValue: "vertical" },
164+
{ name: "fullWidth", defaultValue: "false", changedValue: "true" }
164165
];
165166
propsToForwardToChild.forEach(({ name, defaultValue, changedValue }) => {
166167
it(`change of ${name} prop updates its sgds-tab children`, async () => {

0 commit comments

Comments
 (0)