Skip to main content

VTabs

The VTabs component provides a tabbed interface for organizing content into separate views. It features smooth transitions, responsive behavior, and integrates with VTabsWindow for content panels.

Basic Usage

<template>
  <v-tabs v-model="tab">
    <v-tab value="one">Tab 1</v-tab>
    <v-tab value="two">Tab 2</v-tab>
    <v-tab value="three">Tab 3</v-tab>
  </v-tabs>
  
  <v-tabs-window v-model="tab">
    <v-tabs-window-item value="one">
      Content for Tab 1
    </v-tabs-window-item>
    <v-tabs-window-item value="two">
      Content for Tab 2
    </v-tabs-window-item>
    <v-tabs-window-item value="three">
      Content for Tab 3
    </v-tabs-window-item>
  </v-tabs-window>
</template>

<script setup>
import { ref } from 'vue'

const tab = ref('one')
</script>

Props

modelValue
Currently selected tab value. Use with v-model.
items
TabItem[]
default:"[]"
Array of tab items. Each item can be a string, number, or object with text and value properties.
alignTabs
'start' | 'title' | 'center' | 'end'
default:"'start'"
Alignment of tabs within the container.
color
string
Color applied to the active tab and slider.
bgColor
string
Background color of the tabs bar.
sliderColor
string
Color of the selection slider indicator.
hideSlider
boolean
default:"false"
Hides the slider indicator under the active tab.
fixedTabs
boolean
default:"false"
Makes tabs have equal width with a maximum of 300px each.
grow
boolean
default:"false"
Makes tabs expand to fill available horizontal space.
stacked
boolean
default:"false"
Stacks tab icon and text vertically.
inset
boolean
default:"false"
Applies inset styling to the slider.
insetPadding
string | number
Padding for inset slider.
insetRadius
string | number
Border radius for inset slider.
height
number | string
Height of the tabs bar.
direction
'horizontal' | 'vertical'
default:"'horizontal'"
Orientation of the tabs.
density
'default' | 'comfortable' | 'compact'
Adjusts the vertical spacing of tabs.
selectedClass
string
default:"'v-tab-item--selected'"
CSS class applied to the selected tab.
sliderTransition
'shift' | 'grow' | 'fade'
Animation style for the slider when changing tabs.
sliderTransitionDuration
string | number
Duration of the slider transition animation in milliseconds.
spaced
boolean
Adds spacing between tabs.
showArrows
boolean | 'mobile'
Shows navigation arrows when tabs overflow.
mandatory
boolean | 'force'
default:"'force'"
Forces at least one tab to be selected.
tag
string
default:"'div'"
HTML tag for the root element.

Events

update:modelValue
(value: any) => void
Emitted when the selected tab changes.

Slots

default
Content for the tabs. Usually contains VTab components.
tab
{ item: TabItem }
Slot to customize tab rendering when using items prop.
item
{ item: TabItem }
Slot to customize window item content when using items prop.
window
Additional content in the tabs window.
Slot to customize the previous navigation arrow.
Slot to customize the next navigation arrow.
tab.{value}
{ item: TabItem }
Named slot for specific tab content.
item.{value}
{ item: TabItem }
Named slot for specific window item content.

VTab Props

value
any
Value used when tab is selected.
text
string
Text content of the tab.
icon
IconValue
Icon displayed in the tab.
disabled
boolean
default:"false"
Disables the tab.
to
string | object
Router link destination.
href
string
Anchor link destination.

Items-based Tabs

<template>
  <v-tabs v-model="tab" :items="items">
    <template #item.tab1="{ item }">
      <div>Content for {{ item.text }}</div>
    </template>
    <template #item.tab2="{ item }">
      <div>Content for {{ item.text }}</div>
    </template>
  </v-tabs>
</template>

<script setup>
import { ref } from 'vue'

const tab = ref('tab1')
const items = [
  { text: 'Tab 1', value: 'tab1' },
  { text: 'Tab 2', value: 'tab2' }
]
</script>

Centered Tabs

<template>
  <v-tabs v-model="tab" align-tabs="center">
    <v-tab value="one">Tab 1</v-tab>
    <v-tab value="two">Tab 2</v-tab>
  </v-tabs>
</template>

Fixed Width Tabs

<template>
  <v-tabs v-model="tab" fixed-tabs>
    <v-tab value="one">Tab 1</v-tab>
    <v-tab value="two">Tab 2</v-tab>
    <v-tab value="three">Tab 3</v-tab>
  </v-tabs>
</template>

Growing Tabs

<template>
  <v-tabs v-model="tab" grow>
    <v-tab value="one">Tab 1</v-tab>
    <v-tab value="two">Tab 2</v-tab>
  </v-tabs>
</template>

Vertical Tabs

<template>
  <v-tabs v-model="tab" direction="vertical">
    <v-tab value="one">Tab 1</v-tab>
    <v-tab value="two">Tab 2</v-tab>
  </v-tabs>
</template>

Stacked Tabs with Icons

<template>
  <v-tabs v-model="tab" stacked>
    <v-tab value="one" icon="mdi-home">Home</v-tab>
    <v-tab value="two" icon="mdi-account">Profile</v-tab>
    <v-tab value="three" icon="mdi-cog">Settings</v-tab>
  </v-tabs>
</template>

Examples

Custom Slider Color

<template>
  <v-tabs 
    v-model="tab"
    color="primary"
    slider-color="yellow"
  >
    <v-tab value="one">Tab 1</v-tab>
    <v-tab value="two">Tab 2</v-tab>
  </v-tabs>
</template>

Inset Slider

<template>
  <v-tabs 
    v-model="tab"
    inset
    slider-color="primary"
    bg-color="grey-lighten-3"
  >
    <v-tab value="one">Tab 1</v-tab>
    <v-tab value="two">Tab 2</v-tab>
  </v-tabs>
</template>

Router Integration

<template>
  <v-tabs v-model="tab">
    <v-tab value="home" to="/">Home</v-tab>
    <v-tab value="about" to="/about">About</v-tab>
    <v-tab value="contact" to="/contact">Contact</v-tab>
  </v-tabs>
</template>

Disabled Tab

<template>
  <v-tabs v-model="tab">
    <v-tab value="one">Tab 1</v-tab>
    <v-tab value="two" disabled>Tab 2</v-tab>
    <v-tab value="three">Tab 3</v-tab>
  </v-tabs>
</template>

Custom Transition

<template>
  <v-tabs 
    v-model="tab"
    slider-transition="grow"
    :slider-transition-duration="400"
  >
    <v-tab value="one">Tab 1</v-tab>
    <v-tab value="two">Tab 2</v-tab>
  </v-tabs>
</template>

Dynamic Tabs

<template>
  <v-tabs v-model="tab">
    <v-tab 
      v-for="item in tabs" 
      :key="item.value"
      :value="item.value"
    >
      {{ item.text }}
    </v-tab>
  </v-tabs>
  
  <v-tabs-window v-model="tab">
    <v-tabs-window-item
      v-for="item in tabs"
      :key="item.value"
      :value="item.value"
    >
      {{ item.content }}
    </v-tabs-window-item>
  </v-tabs-window>
</template>

<script setup>
import { ref } from 'vue'

const tab = ref('tab1')
const tabs = [
  { text: 'Tab 1', value: 'tab1', content: 'Content 1' },
  { text: 'Tab 2', value: 'tab2', content: 'Content 2' },
  { text: 'Tab 3', value: 'tab3', content: 'Content 3' }
]
</script>

Accessibility

  • Uses role="tablist" on the tabs container
  • Uses role="tab" on individual tabs
  • Sets aria-selected on the active tab
  • Manages tabindex for keyboard navigation
  • Tab content panels should use role="tabpanel"

Slider Transitions

Shift (Default)

The slider smoothly shifts from the previous tab to the new tab, scaling dynamically.

Grow

The slider scales from 0 to full size at the new tab position.

Fade

The slider fades in at the new tab position. Transition durations:
  • Shift: 225ms (default)
  • Grow: 350ms (default)
  • Fade: 400ms (default)

Build docs developers (and LLMs) love