diff --git a/registry/components/tabs-slide-indicator/demo.html b/registry/components/tabs-slide-indicator/demo.html
index 99c36446a8..d4afca005f 100644
--- a/registry/components/tabs-slide-indicator/demo.html
+++ b/registry/components/tabs-slide-indicator/demo.html
@@ -54,6 +54,8 @@
background: #18181b;
transform: translateX(var(--hf-tab-x));
box-shadow: 0 12px 26px rgba(0, 0, 0, 0.18);
+ overflow: hidden;
+ z-index: 2;
}
.hf-transition-tabs-slide-indicator button {
position: relative;
@@ -61,10 +63,19 @@
height: 36px;
border: 0;
background: transparent;
- color: #71717a;
+ color: #6b6b73;
font-weight: 600;
}
- .hf-transition-tabs-slide-indicator button:nth-of-type(2) {
+ .hf-transition-tabs-slide-indicator .indicator-labels {
+ position: absolute;
+ top: 0;
+ left: 0;
+ display: grid;
+ grid-template-columns: repeat(3, 86px);
+ transform: translateX(calc(var(--hf-tab-x) * -1));
+ pointer-events: none;
+ }
+ .hf-transition-tabs-slide-indicator .indicator-labels button {
color: #fff;
}
@@ -88,7 +99,12 @@
{ "id": "labels", "type": "string", "role": "content", "label": "Labels", "description": "The tab names, separated by commas. Two or more names rebuild the row.", "default": "Plan,Debug,Ask" }
]'
>
-
@@ -117,6 +133,17 @@
return Object.prototype.hasOwnProperty.call(table, value) ? value : fallback;
}
+ // The mirrored copy is decorative: it repeats a label the row
+ // already carries, so it stays out of the tab order.
+ function makeTab(text, mirrored) {
+ var button = document.createElement("button");
+ button.textContent = text;
+ if (mirrored) {
+ button.tabIndex = -1;
+ }
+ return button;
+ }
+
var accent = accents[pick(accents, vars.accent, "ink")];
var width = widths[pick(widths, vars.width, "standard")];
var radius = shapes[pick(shapes, vars.shape, "pill")];
@@ -140,14 +167,18 @@
roots[i].style.setProperty("--hf-tab-radius", radius);
// A single tab has nowhere to slide to, so it is left as authored.
if (labels.length > 1) {
+ // Every label exists twice: once in the row and once in the
+ // clipped copy the pill carries, so both are rebuilt together.
+ var mirror = roots[i].querySelector(".indicator-labels");
var old = roots[i].querySelectorAll("button");
for (var j = 0; j < old.length; j += 1) {
old[j].parentNode.removeChild(old[j]);
}
for (var k = 0; k < labels.length; k += 1) {
- var button = document.createElement("button");
- button.textContent = labels[k];
- roots[i].appendChild(button);
+ roots[i].appendChild(makeTab(labels[k], false));
+ if (mirror) {
+ mirror.appendChild(makeTab(labels[k], true));
+ }
}
roots[i].style.setProperty("--hf-tab-count", String(labels.length));
}
@@ -190,6 +221,8 @@
background: var(--hf-tab-fill, #18181b);
transform: translateX(calc(var(--hf-tab-x) * var(--hf-tab-step, 1)));
box-shadow: 0 12px 26px rgba(0, 0, 0, 0.18);
+ overflow: hidden;
+ z-index: 2;
}
.hf-transition-tabs-slide-indicator button {
position: relative;
@@ -197,10 +230,19 @@
height: 36px;
border: 0;
background: transparent;
- color: #71717a;
+ color: #6b6b73;
font-weight: 850;
}
- .hf-transition-tabs-slide-indicator button:nth-of-type(2) {
+ .hf-transition-tabs-slide-indicator .indicator-labels {
+ position: absolute;
+ top: 0;
+ left: 0;
+ display: grid;
+ grid-template-columns: repeat(var(--hf-tab-count, 3), var(--hf-tab-width, 86px));
+ transform: translateX(calc(var(--hf-tab-x) * var(--hf-tab-step, 1) * -1));
+ pointer-events: none;
+ }
+ .hf-transition-tabs-slide-indicator .indicator-labels button {
color: #fff;
}
diff --git a/registry/components/tabs-slide-indicator/tabs-slide-indicator.html b/registry/components/tabs-slide-indicator/tabs-slide-indicator.html
index d472843d4f..3512e5eeeb 100644
--- a/registry/components/tabs-slide-indicator/tabs-slide-indicator.html
+++ b/registry/components/tabs-slide-indicator/tabs-slide-indicator.html
@@ -39,7 +39,12 @@
{ "id": "labels", "type": "string", "role": "content", "label": "Labels", "description": "The tab names, separated by commas. Two or more names rebuild the row.", "default": "Plan,Debug,Ask" }
]'
>
-
+
@@ -104,6 +124,17 @@
return Object.prototype.hasOwnProperty.call(table, value) ? value : fallback;
}
+ // The mirrored copy is decorative: it repeats a label the row already
+ // carries, so it stays out of the tab order.
+ function makeTab(text, mirrored) {
+ var button = document.createElement("button");
+ button.textContent = text;
+ if (mirrored) {
+ button.tabIndex = -1;
+ }
+ return button;
+ }
+
var accent = accents[pick(accents, vars.accent, "ink")];
var width = widths[pick(widths, vars.width, "standard")];
var radius = shapes[pick(shapes, vars.shape, "pill")];
@@ -127,14 +158,18 @@
roots[i].style.setProperty("--hf-tab-radius", radius);
// A single tab has nowhere to slide to, so it is left as authored.
if (labels.length > 1) {
+ // Every label exists twice: once in the row and once in the clipped
+ // copy the pill carries, so both have to be rebuilt together.
+ var mirror = roots[i].querySelector(".indicator-labels");
var old = roots[i].querySelectorAll("button");
for (var j = 0; j < old.length; j += 1) {
old[j].parentNode.removeChild(old[j]);
}
for (var k = 0; k < labels.length; k += 1) {
- var button = document.createElement("button");
- button.textContent = labels[k];
- roots[i].appendChild(button);
+ roots[i].appendChild(makeTab(labels[k], false));
+ if (mirror) {
+ mirror.appendChild(makeTab(labels[k], true));
+ }
}
roots[i].style.setProperty("--hf-tab-count", String(labels.length));
}