| title | Tabs | |||||||
|---|---|---|---|---|---|---|---|---|
| status | ready | |||||||
| thumb | true | |||||||
| description | Tabs allow users to navigation between grouped content in different views while within the same page context. | |||||||
| storybook | https://dialtone.dialpad.com/vue/?path=/story/components-tabs--default | |||||||
| figma_url | https://www.figma.com/design/W58r5BkO8qTw3vem9YieJd/DT9-Component-Library--Rebrand-2025-?node-id=2129-4760 | |||||||
| keywords |
|
<div class="d-w100p">
<example-tabs />
</div>
<!-- @code -->
<dt-tab-group>
<template #tabs>
<dt-tab id="1" panel-id="2" selected>First</dt-tab>
<dt-tab id="3" panel-id="4">Second</dt-tab>
<dt-tab id="5" panel-id="6">Third</dt-tab>
</template>
</dt-tab-group>Remove the bottom border of any tablist.
<div class="d-w100p">
<example-tabs borderless />
</div>
<!-- @code -->
<dt-tab-group borderless>
...
</dt-tab-group>All tabs render as muted buttons. The selected tab is distinguished with active styling.
<div class="d-w100p">
<example-tabs kind="muted" />
</div>
<!-- @code -->
<dt-tab-group kind="muted">
<template #tabs>
<dt-tab id="1" panel-id="2" selected>First</dt-tab>
<dt-tab id="3" panel-id="4">Second</dt-tab>
<dt-tab id="5" panel-id="6">Third</dt-tab>
</template>
</dt-tab-group>The selected tab renders with an outlined border instead of a filled style.
<div class="d-w100p">
<example-tabs outlined />
</div>
<!-- @code -->
<dt-tab-group outlined>
<template #tabs>
<dt-tab id="1" panel-id="2" selected>First</dt-tab>
<dt-tab id="3" panel-id="4">Second</dt-tab>
<dt-tab id="5" panel-id="6">Third</dt-tab>
</template>
</dt-tab-group>Combines muted kind with outlined selected state.
<div class="d-w100p">
<example-tabs kind="muted" outlined />
</div>
<!-- @code -->
<dt-tab-group kind="muted" outlined>
<template #tabs>
<dt-tab id="1" panel-id="2" selected>First</dt-tab>
<dt-tab id="3" panel-id="4">Second</dt-tab>
<dt-tab id="5" panel-id="6">Third</dt-tab>
</template>
</dt-tab-group>Add disabled to a specific tab.
<dt-tab-group>
<template #tabs>
<dt-tab id="1" panel-id="2" selected>First</dt-tab>
<dt-tab id="3" panel-id="4">Second</dt-tab>
<dt-tab id="5" panel-id="6">Third</dt-tab>
<dt-tab id="7" panel-id="8" disabled>Fourth</dt-tab>
</template>
</dt-tab-group>Add disabled to the tab group to disable all.
<example-tabs disabled />
<!-- @code -->
<dt-tab-group disabled>
<template #tabs>
<dt-tab id="1" panel-id="2" selected>First</dt-tab>
<dt-tab id="3" panel-id="4">Second</dt-tab>
<dt-tab id="5" panel-id="6">Third</dt-tab>
</template>
</dt-tab-group>[!WARNING] Deprecated The
invertedprop has been deprecated. Use the v-dt-mode directive instead.
In place of the inverted prop, use the v-dt-mode directive on the component element.
<div class="d-p-100 d-bgc-contrast d-w100p">
<div v-dt-mode:invert class="d-p-200 d-bar8">
<example-tabs />
</div>
</div>
<!-- @code -->
<dt-tab-group v-dt-mode:invert>
<template #tabs>
<dt-tab id="1" panel-id="2" selected>First</dt-tab>
<dt-tab id="3" panel-id="4">Second</dt-tab>
</template>
</dt-tab-group>Control how tabs distribute available horizontal space within the tab list. It only applies to horizontal tabs, and has no effect with orientation="vertical".
Tabs expand proportionally to fill the container. Longer labels receive more space.
<!-- @wrapper -->
<div class="d-w100p">
<dt-tab-group spread="grow">
<template #tabs>
<dt-tab id="sg1" panel-id="sg2" selected>Tab 1</dt-tab>
<dt-tab id="sg3" panel-id="sg4">Tab the second</dt-tab>
<dt-tab id="sg5" panel-id="sg6">Tab the third</dt-tab>
</template>
</dt-tab-group>
</div>All tabs share the same width, regardless of label length.
<!-- @wrapper -->
<div class="d-w-800">
<dt-tab-group spread="equal">
<template #tabs>
<dt-tab id="se1" panel-id="se2" selected>Tab 1</dt-tab>
<dt-tab id="se3" panel-id="se4">Tab the second</dt-tab>
<dt-tab id="se5" panel-id="se6">Tab the third</dt-tab>
</template>
</dt-tab-group>
</div><dt-stack gap="200" class="d-w100p">
<dt-tab-group :size="100">
<template #tabs>
<dt-tab id="1" panel-id="2" selected>
First
</dt-tab>
<dt-tab id="3" panel-id="4">
Second
</dt-tab>
<dt-tab id="5" panel-id="6">
Third
</dt-tab>
</template>
</dt-tab-group>
<dt-tab-group :size="200">
<template #tabs>
<dt-tab id="1" panel-id="2" selected>
First
</dt-tab>
<dt-tab id="3" panel-id="4">
Second
</dt-tab>
<dt-tab id="5" panel-id="6">
Third
</dt-tab>
</template>
</dt-tab-group>
<dt-tab-group>
<template #tabs>
<dt-tab id="1" panel-id="2" selected>
First
</dt-tab>
<dt-tab id="3" panel-id="4">
Second
</dt-tab>
<dt-tab id="5" panel-id="6">
Third
</dt-tab>
</template>
</dt-tab-group>
<dt-tab-group :size="400">
<template #tabs>
<dt-tab id="1" panel-id="2" selected>
First
</dt-tab>
<dt-tab id="3" panel-id="4">
Second
</dt-tab>
<dt-tab id="5" panel-id="6">
Third
</dt-tab>
</template>
</dt-tab-group>
<dt-tab-group :size="500">
<template #tabs>
<dt-tab id="1" panel-id="2" selected>
First
</dt-tab>
<dt-tab id="3" panel-id="4">
Second
</dt-tab>
<dt-tab id="5" panel-id="6">
Third
</dt-tab>
</template>
</dt-tab-group>
</dt-stack>
<!-- @code -->
<dt-tab-group :size="100|200|300|400|500">
...
</dt-tab-group>Use the #startIcon or #endIcon slot on dt-tab to add an icon. The slot provides iconSize to match the tab's size.
[!WARNING] Deprecated The
#iconslot has been deprecated. Use#startIconor#endIconinstead.
<!-- @wrapper -->
<div class="d-w100p">
<dt-tab-group>
<template #tabs>
<dt-tab id="1" panel-id="2" selected>
First
<template #startIcon="{ iconSize }">
<dt-icon name="box-select" :size="iconSize" />
</template>
</dt-tab>
<dt-tab id="3" panel-id="4">
Second
<template #startIcon="{ iconSize }">
<dt-icon name="box-select" :size="iconSize" />
</template>
<template #endIcon="{ iconSize }">
<dt-icon name="box-select" :size="iconSize" />
</template>
</dt-tab>
<dt-tab id="5" panel-id="6">
Third
<template #endIcon="{ iconSize }">
<dt-icon name="box-select" :size="iconSize" />
</template>
</dt-tab>
</template>
</dt-tab-group>
</div>Use the #leading and #trailing slots on dt-tab to render content like badges or count indicators alongside tab labels. Use leading-class and trailing-class to adjust padding.
<!-- @wrapper -->
<div class="d-w100p">
<dt-tab-group>
<template #tabs>
<dt-tab id="lt1" panel-id="lt2" selected trailing-class="d-pie-100">
Inbox
<template #trailing>
<dt-badge kind="count" type="bulletin" text="9" />
</template>
</dt-tab>
<dt-tab id="lt3" panel-id="lt4" trailing-class="d-pie-100">
Archive
<template #trailing>
<dt-badge kind="count" text="99+" />
</template>
</dt-tab>
<dt-tab id="lt5" panel-id="lt6">
Drafts
</dt-tab>
</template>
</dt-tab-group>
</div>Set orientation="vertical" to stack tabs vertically alongside the panel.
<example-tabs orientation="vertical" />
<!-- @code -->
<dt-tab-group orientation="vertical">
<template #tabs>
<dt-tab id="1" panel-id="2" selected>First</dt-tab>
<dt-tab id="3" panel-id="4">Second</dt-tab>
<dt-tab id="5" panel-id="6">Third</dt-tab>
</template>
</dt-tab-group>By default, tabs use manual activation — the user must press Enter or Space after focusing a tab to select it. Set activation-mode="auto" to select tabs immediately on focus via arrow keys, following the WAI-ARIA Tabs pattern.
<example-tabs activation-mode="auto" />
<!-- @code -->
<dt-tab-group activation-mode="auto">
<template #tabs>
<dt-tab id="1" panel-id="2" selected>First</dt-tab>
<dt-tab id="3" panel-id="4">Second</dt-tab>
<dt-tab id="5" panel-id="6">Third</dt-tab>
</template>
</dt-tab-group>If you need to do some validation before changing tabs, you can use the before-change event. If the event handler is prevented, the tab change will be cancelled.
<example-tabs validate />
<!-- @code -->
<dt-tab-group @before-change="confirmBeforeLeave">
<template #tabs>
<dt-tab id="1" panel-id="2" selected>First</dt-tab>
<dt-tab id="3" panel-id="4">Second</dt-tab>
<dt-tab id="5" panel-id="6">Third</dt-tab>
</template>
</dt-tab-group>
<script setup>
function confirmBeforeLeave (event) {
const confirmed = confirm("Are you sure to change tab?");
if (!confirmed) {
event.preventDefault();
}
}
</script>To create accessible tabs, be sure to implement the proper keyboard navigation and utilize the following ARIA roles to properly declare element roles, content relationships, and current status:
<script setup> import ExampleTabs from "@exampleComponents/ExampleTabs.vue"; </script>