mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-17 05:28:09 +01:00
367 lines
8.8 KiB
Markdown
367 lines
8.8 KiB
Markdown
---
|
|
description: A set of tab panels that are displayed one at a time.
|
|
links:
|
|
- label: GitHub
|
|
icon: i-simple-icons-github
|
|
to: https://github.com/nuxt/ui/blob/dev/src/runtime/components/navigation/Tabs.vue
|
|
---
|
|
|
|
## 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.
|
|
|
|
::component-example
|
|
#default
|
|
:tabs-example-basic{class="w-full"}
|
|
|
|
#code
|
|
```vue
|
|
<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`.
|
|
|
|
::component-example
|
|
#default
|
|
:tabs-example-vertical{class="w-full"}
|
|
|
|
#code
|
|
```vue
|
|
<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.
|
|
|
|
::component-example
|
|
#default
|
|
:tabs-example-index{class="w-full"}
|
|
|
|
#code
|
|
```vue
|
|
<script setup>
|
|
const items = [...]
|
|
</script>
|
|
|
|
<template>
|
|
<UTabs :items="items" :default-index="2" />
|
|
</template>
|
|
```
|
|
::
|
|
|
|
::callout{icon="i-heroicons-exclamation-triangle"}
|
|
This will have no effect if you are using a `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.
|
|
|
|
::component-example
|
|
#default
|
|
:tabs-example-change{class="w-full"}
|
|
|
|
#code
|
|
```vue
|
|
<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.
|
|
|
|
::component-example
|
|
#default
|
|
:tabs-example-v-model{class="w-full"}
|
|
|
|
#code
|
|
```vue
|
|
<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>
|
|
```
|
|
::
|
|
|
|
::callout{icon="i-heroicons-information-circle"}
|
|
In this example, we are binding tabs to the route query. Refresh the page to see the selected tab change.
|
|
::
|
|
|
|
## 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.
|
|
|
|
::component-example
|
|
#default
|
|
:tabs-example-default-slot
|
|
|
|
#code
|
|
```vue
|
|
<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.
|
|
|
|
::component-example
|
|
#default
|
|
:tabs-example-item-slot
|
|
|
|
#code
|
|
```vue
|
|
<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.
|
|
|
|
::component-example
|
|
#default
|
|
:tabs-example-item-custom-slot
|
|
|
|
#code
|
|
```vue
|
|
<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
|
|
|
|
:component-props
|
|
|
|
## Preset
|
|
|
|
:component-preset
|