navigation
Tabs
A set of tab panels that are displayed one at a time.
Usage
Pass an array to the items
prop of the Tabs component. Each item can have the following properties:
label
- The label of the item.slot
- A key to customize the item with a slot.content
- The content to display in the panel by default.disabled
- Determines whether the item is disabled or not.
<script setup>const items = [{ label: 'Tab1', content: 'This is the content shown for Tab1'}, { label: 'Tab2', disabled: true, content: 'And, this is the content for Tab2'}, { label: 'Tab3', content: 'Finally, this is the content for Tab3'}]</script><template> <UTabs :items="items" /></template>
Vertical
You can change the orientation of the tabs by setting the orientation
prop to vertical
.
<script setup>const items = [...]</script><template> <UTabs :items="items" orientation="vertical" :ui="{ wrapper: 'flex items-center gap-4', list: { width: 'w-48' } }" /></template>
Default index
You can set the default index of the tabs by setting the default-index
prop.
<script setup>const items = [...]</script><template> <UTabs :items="items" :default-index="2" /></template>
v-model
to control the selected index.Listen to changes
You can listen to changes by using the @change
event. The event will emit the index of the selected item.
<script setup>const items = [...]function onChange (index) { const item = items[index] alert(`${item.label} was clicked!`)}</script><template> <UTabs :items="items" @change="onChange" /></template>
Control the selected index
Use a v-model
to control the selected index.
<script setup>const items = [...]const route = useRoute()const router = useRouter()const selected = computed({ get () { const index = items.findIndex((item) => item.label === route.query.tab) if (index === -1) { return 0 } return index }, set (value) { // Hash is specified here to prevent the page from scrolling to the top router.replace({ query: { tab: items[value].label }, hash: '#control-the-selected-index' }) }})</script><template> <UTabs v-model="selected" :items="items" /></template>
Slots
You can use slots to customize the buttons and items content of the Accordion.
default
Use the #default
slot to customize the content of the trigger buttons. You will have access to the item
, index
, selected
and disabled
in the slot scope.
<script setup>const items = [{ label: 'Introduction', icon: 'i-heroicons-information-circle', content: 'This is the content shown for Tab1'}, { label: 'Installation', icon: 'i-heroicons-arrow-down-tray', content: 'And, this is the content for Tab2'}, { label: 'Theming', icon: 'i-heroicons-eye-dropper', content: 'Finally, this is the content for Tab3'}]</script><template> <UTabs :items="items" class="w-full"> <template #default="{ item, index, selected }"> <div class="flex items-center gap-2 relative truncate"> <UIcon :name="item.icon" class="w-4 h-4 flex-shrink-0" /> <span class="truncate">{{ index + 1 }}. {{ item.label }}</span> <span v-if="selected" class="absolute -right-4 w-2 h-2 rounded-full bg-primary-500 dark:bg-primary-400" /> </div> </template> </UTabs></template>
item
Use the #item
slot to customize the items content. You will have access to the item
, index
and selected
properties in the slot scope.
<script setup>const items = [{ key: 'account', label: 'Account', description: 'Make changes to your account here. Click save when you\'re done.'}, { key: 'password', label: 'Password', description: 'Change your password here. After saving, you\'ll be logged out.'}]const accountForm = reactive({ name: 'Benjamin', username: 'benjamincanac' })const passwordForm = reactive({ currentPassword: '', newPassword: '' })function onSubmit (form) { console.log('Submitted form:', form)}</script><template> <UTabs :items="items" class="w-full"> <template #item="{ item }"> <UCard @submit.prevent="() => onSubmit(item.key === 'account' ? accountForm : passwordForm)"> <template #header> <h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white"> {{ item.label }} </h3> <p class="mt-1 text-sm text-gray-500 dark:text-gray-400"> {{ item.description }} </p> </template> <div v-if="item.key === 'account'" class="space-y-3"> <UFormGroup label="Name" name="name"> <UInput v-model="accountForm.name" /> </UFormGroup> <UFormGroup label="Username" name="username"> <UInput v-model="accountForm.username" /> </UFormGroup> </div> <div v-else-if="item.key === 'password'" class="space-y-3"> <UFormGroup label="Current Password" name="current" required> <UInput v-model="passwordForm.currentPassword" type="password" required /> </UFormGroup> <UFormGroup label="New Password" name="new" required> <UInput v-model="passwordForm.newPassword" type="password" required /> </UFormGroup> </div> <template #footer> <UButton type="submit" color="black"> Save {{ item.key === 'account' ? 'account' : 'password' }} </UButton> </template> </UCard> </template> </UTabs></template>
You can also pass a slot
property to customize a specific item.
<script setup>const items = [{ slot: 'account', label: 'Account'}, { slot: 'password', label: 'Password'}]const accountForm = reactive({ name: 'Benjamin', username: 'benjamincanac' })const passwordForm = reactive({ currentPassword: '', newPassword: '' })function onSubmitAccount () { console.log('Submitted form:', accountForm)}function onSubmitPassword () { console.log('Submitted form:', passwordForm)}</script><template> <UTabs :items="items" class="w-full"> <template #account="{ item }"> <UCard @submit.prevent="onSubmitAccount"> <template #header> <h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white"> {{ item.label }} </h3> <p class="mt-1 text-sm text-gray-500 dark:text-gray-400"> Make changes to your account here. Click save when you're done. </p> </template> <UFormGroup label="Name" name="name" class="mb-3"> <UInput v-model="accountForm.name" /> </UFormGroup> <UFormGroup label="Username" name="username"> <UInput v-model="accountForm.username" /> </UFormGroup> <template #footer> <UButton type="submit" color="black"> Save account </UButton> </template> </UCard> </template> <template #password="{ item }"> <UCard @submit.prevent="onSubmitPassword"> <template #header> <h3 class="text-base font-semibold leading-6 text-gray-900 dark:text-white"> {{ item.label }} </h3> <p class="mt-1 text-sm text-gray-500 dark:text-gray-400"> Change your password here. After saving, you'll be logged out. </p> </template> <UFormGroup label="Current Password" name="current" required class="mb-3"> <UInput v-model="passwordForm.currentPassword" type="password" required /> </UFormGroup> <UFormGroup label="New Password" name="new" required> <UInput v-model="passwordForm.newPassword" type="password" required /> </UFormGroup> <template #footer> <UButton type="submit" color="black"> Save password </UButton> </template> </UCard> </template> </UTabs></template>
Props
undefined
undefined
"horizontal"
0
[]
Preset
{ "wrapper": "relative space-y-2", "container": "relative w-full", "base": "focus:outline-none", "list": { "base": "relative", "background": "bg-gray-100 dark:bg-gray-800", "rounded": "rounded-lg", "shadow": "", "padding": "p-1", "height": "h-10", "width": "w-full", "marker": { "wrapper": "absolute top-[4px] left-[4px] duration-200 ease-out focus:outline-none", "base": "w-full h-full", "background": "bg-white dark:bg-gray-900", "rounded": "rounded-md", "shadow": "shadow-sm" }, "tab": { "base": "relative inline-flex items-center justify-center flex-shrink-0 w-full ui-focus-visible:outline-0 ui-focus-visible:ring-2 ui-focus-visible:ring-primary-500 dark:ui-focus-visible:ring-primary-400 ui-not-focus-visible:outline-none focus:outline-none disabled:cursor-not-allowed disabled:opacity-75 transition-colors duration-200 ease-out", "background": "", "active": "text-gray-900 dark:text-white", "inactive": "text-gray-500 dark:text-gray-400", "height": "h-8", "padding": "px-3", "size": "text-sm", "font": "font-medium", "rounded": "rounded-md", "shadow": "" } }}