A set of tab panels that are displayed one at a time.

Usage

Items

Use the items prop as an array of objects with the following properties:

  • label?: string
  • icon?: string
  • avatar?: AvatarProps
  • content?: string
  • value?: string | number
  • disabled?: boolean
  • slot?: string
This is the account content.
<script setup lang="ts">
const items = ref([
  {
    label: 'Account',
    icon: 'i-lucide-user',
    content: 'This is the account content.'
  },
  {
    label: 'Password',
    icon: 'i-lucide-lock',
    content: 'This is the password content.'
  }
])
</script>

<template>
  <UTabs :items="items" class="w-full" />
</template>

Content

Set the content prop to false to turn the Tabs into a toggle-only control without displaying any content. Defaults to true.

<script setup lang="ts">
const items = ref([
  {
    label: 'Account',
    icon: 'i-lucide-user',
    content: 'This is the account content.'
  },
  {
    label: 'Password',
    icon: 'i-lucide-lock',
    content: 'This is the password content.'
  }
])
</script>

<template>
  <UTabs :content="false" :items="items" class="w-full" />
</template>

Unmount

Use the unmount-on-hide prop to prevent the content from being unmounted when the Tabs is collapsed. Defaults to true.

This is the account content.
<script setup lang="ts">
const items = ref([
  {
    label: 'Account',
    icon: 'i-lucide-user',
    content: 'This is the account content.'
  },
  {
    label: 'Password',
    icon: 'i-lucide-lock',
    content: 'This is the password content.'
  }
])
</script>

<template>
  <UTabs :unmount-on-hide="false" :items="items" class="w-full" />
</template>
You can inspect the DOM to see each item's content being rendered.

Color

Use the color prop to change the color of the Tabs.

<script setup lang="ts">
const items = ref([
  {
    label: 'Account'
  },
  {
    label: 'Password'
  }
])
</script>

<template>
  <UTabs color="neutral" :content="false" :items="items" class="w-full" />
</template>

Variant

Use the variant prop to change the variant of the Tabs.

<script setup lang="ts">
const items = ref([
  {
    label: 'Account'
  },
  {
    label: 'Password'
  }
])
</script>

<template>
  <UTabs color="neutral" variant="link" :content="false" :items="items" class="w-full" />
</template>

Size

Use the size prop to change the size of the Tabs.

<script setup lang="ts">
const items = ref([
  {
    label: 'Account'
  },
  {
    label: 'Password'
  }
])
</script>

<template>
  <UTabs :content="false" :items="items" class="w-full" />
</template>

Orientation

Use the orientation prop to change the orientation of the Tabs. Defaults to horizontal.

<script setup lang="ts">
const items = ref([
  {
    label: 'Account'
  },
  {
    label: 'Password'
  }
])
</script>

<template>
  <UTabs orientation="vertical" :content="false" :items="items" class="w-full" />
</template>

Examples

Control active item

You can control the active item by using the default-value prop or the v-model directive with the index of the item.

<script setup lang="ts">
const items = [
  {
    label: 'Account'
  },
  {
    label: 'Password'
  }
]

const active = ref('0')

// Note: This is for demonstration purposes only. Don't do this at home.
onMounted(() => {
  setInterval(() => {
    active.value = String((Number(active.value) + 1) % items.length)
  }, 2000)
})
</script>

<template>
  <UTabs v-model="active" :content="false" :items="items" class="w-full" />
</template>
You can also pass the value of one of the items if provided.

With content slot

Use the #content slot to customize the content of each item.

This is the Account tab.

<script setup lang="ts">
const items = [
  {
    label: 'Account',
    icon: 'i-lucide-user'
  },
  {
    label: 'Password',
    icon: 'i-lucide-lock'
  }
]
</script>

<template>
  <UTabs :items="items" class="w-full">
    <template #content="{ item }">
      <p>This is the {{ item.label }} tab.</p>
    </template>
  </UTabs>
</template>

With custom slot

Use the slot property to customize a specific item.

Make changes to your account here. Click save when you're done.

<script setup lang="ts">
const items = [
  {
    label: 'Account',
    description: 'Make changes to your account here. Click save when you\'re done.',
    icon: 'i-lucide-user',
    slot: 'account'
  },
  {
    label: 'Password',
    description: 'Change your password here. After saving, you\'ll be logged out.',
    icon: 'i-lucide-lock',
    slot: 'password'
  }
]

const state = reactive({
  name: 'Benjamin Canac',
  username: 'benjamincanac',
  currentPassword: '',
  newPassword: '',
  confirmPassword: ''
})
</script>

<template>
  <UTabs :items="items" variant="link" class="gap-4 w-full" :ui="{ trigger: 'flex-1' }">
    <template #account="{ item }">
      <p class="text-[var(--ui-text-muted)] mb-4">
        {{ item.description }}
      </p>

      <UForm :state="state" class="flex flex-col gap-4">
        <UFormField label="Name" name="name">
          <UInput v-model="state.name" class="w-full" />
        </UFormField>
        <UFormField label="Username" name="username">
          <UInput v-model="state.username" class="w-full" />
        </UFormField>

        <UButton label="Save changes" type="submit" variant="soft" class="self-end" />
      </UForm>
    </template>

    <template #password="{ item }">
      <p class="text-[var(--ui-text-muted)] mb-4">
        {{ item.description }}
      </p>

      <UForm :state="state" class="flex flex-col gap-4">
        <UFormField label="Current Password" name="current" required>
          <UInput v-model="state.currentPassword" type="password" required class="w-full" />
        </UFormField>
        <UFormField label="New Password" name="new" required>
          <UInput v-model="state.newPassword" type="password" required class="w-full" />
        </UFormField>
        <UFormField label="Confirm Password" name="confirm" required>
          <UInput v-model="state.confirmPassword" type="password" required class="w-full" />
        </UFormField>

        <UButton label="Change password" type="submit" variant="soft" class="self-end" />
      </UForm>
    </template>
  </UTabs>
</template>

API

Props

Prop Default Type
as

'div'

any

The element or component this component should render as.

items

TabsItem[]

color

'primary'

"error" | "primary" | "secondary" | "success" | "info" | "warning" | "neutral"

variant

'pill'

"link" | "pill"

size

'md'

"md" | "xs" | "sm" | "lg" | "xl"

orientation

'horizontal'

"vertical" | "horizontal"

The orientation of the tabs.

content

true

boolean

The content of the tabs, can be disabled to prevent rendering the content.

labelKey

'label'

string

The key used to get the label from the item.

defaultValue

'0'

string | number

The value of the tab that should be active when initially rendered. Use when you do not need to control the state of the tabs

modelValue

string | number

The controlled value of the tab to activate. Can be bind as v-model.

unmountOnHide

true

boolean

When true, the element will be unmounted on closed state.

activationMode

automatic

"automatic" | "manual"

Whether a tab is activated automatically (on focus) or manually (on click).

ui

PartialString<{ root: string; list: string; indicator: string; trigger: string[]; content: string; leadingIcon: string; leadingAvatar: string; leadingAvatarSize: string; label: string; }>

Slots

Slot Type
leading

{ item: TabsItem; index: number; }

default

{ item: TabsItem; index: number; }

trailing

{ item: TabsItem; index: number; }

content

{ item: TabsItem; index: number; }

Emits

Event Type
update:modelValue

[payload: string | number]

Theme

app.config.ts
export default defineAppConfig({
  uiPro: {
    prose: {
      tabs: {
        slots: {
          root: 'my-5'
        }
      },
      tabsItem: {
        base: ''
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      uiPro: {
        prose: {
          tabs: {
            slots: {
              root: 'my-5'
            }
          },
          tabsItem: {
            base: ''
          }
        }
      }
    })
  ]
})