Underline Tabs
A keyboard-accessible tab strip with the active tab underlined.
6 个框架中级
A segmented control where the selected tab becomes a filled pill.
<!--
Pills: the tablist is a tinted track and the selected tab is a filled pill
inside it. Same roles, same roving tabindex, same arrow keys as every other
tabs entry - only the paint changes.
-->
<div class="tabs-pills" data-tabs-pills>
<div class="tabs-pills__list" role="tablist" aria-label="Report range">
<button class="tabs-pills__tab" type="button" role="tab" id="pill-day" aria-controls="pill-panel-day" aria-selected="true" tabindex="0">
Day
</button>
<button class="tabs-pills__tab" type="button" role="tab" id="pill-week" aria-controls="pill-panel-week" aria-selected="false" tabindex="-1">
Week
</button>
<button class="tabs-pills__tab" type="button" role="tab" id="pill-month" aria-controls="pill-panel-month" aria-selected="false" tabindex="-1">
Month
</button>
</div>
<div class="tabs-pills__panel" role="tabpanel" id="pill-panel-day" aria-labelledby="pill-day" tabindex="0">
<p>1,284 requests served today with a median latency of 42ms.</p>
</div>
<div class="tabs-pills__panel" role="tabpanel" id="pill-panel-week" aria-labelledby="pill-week" tabindex="0" hidden>
<p>9,731 requests this week - up 12% on the week before.</p>
</div>
<div class="tabs-pills__panel" role="tabpanel" id="pill-panel-month" aria-labelledby="pill-month" tabindex="0" hidden>
<p>41,208 requests this month, with no incidents recorded.</p>
</div>
</div>
<script>
(function () {
document.querySelectorAll('[data-tabs-pills]').forEach(function (root) {
var tabs = Array.prototype.slice.call(root.querySelectorAll('[role="tab"]'));
var panels = Array.prototype.slice.call(root.querySelectorAll('[role="tabpanel"]'));
function select(index, setFocus) {
tabs.forEach(function (tab, i) {
var isSelected = i === index;
tab.setAttribute('aria-selected', String(isSelected));
tab.tabIndex = isSelected ? 0 : -1;
if (panels[i]) panels[i].hidden = !isSelected;
});
if (setFocus) tabs[index].focus();
}
tabs.forEach(function (tab, i) {
tab.addEventListener('click', function () {
select(i, false);
});
tab.addEventListener('keydown', function (event) {
var next = -1;
if (event.key === 'ArrowRight') next = (i + 1) % tabs.length;
else if (event.key === 'ArrowLeft') next = (i - 1 + tabs.length) % tabs.length;
else if (event.key === 'Home') next = 0;
else if (event.key === 'End') next = tabs.length - 1;
else return;
event.preventDefault();
select(next, true);
});
});
});
})();
</script>| Prop | 类型 | 默认值 | 说明 |
|---|---|---|---|
items必填 | TabItem[] | - | 要渲染的项目数组。 |
defaultTabId | string | - | 挂载时默认展开项的 id。 |
onSelect | (id: string) => void | - | 用户选择菜单项时触发,参数为所选项。 |
className | string | - | 合并到根元素上的额外类名。 |
The tinted track is the `tablist` itself, so the pills have nothing to align against but their own container - adjust `p-1` and the gap together or the pill will not sit centred. The fill stays `blue-600` in dark mode on purpose: white text on `blue-500` measures 3.7:1 and fails AA, while `blue-600` holds 5.2:1 on both themes. Best for two to four short, mutually exclusive options; longer labels want the underline variant.