Tabs
Organizes content into separate panels that users can switch between. Makes navigating related sections quick and intuitive.
Orientation
vue
<script setup lang="ts">
import { reactive } from 'vue'
import { Tabs } from 'frappe-ui'
const state = reactive({
index: 0,
tabs: [
{
label: 'Github',
content:
'Github is a code hosting platform for version control and collaboration',
},
{
label: 'Twitter',
content:
'Twitter is an American microblogging and social networking service on which users post',
},
{
label: 'Linkedin',
content:
'LinkedIn is an American business and employment-oriented online service',
},
],
})
</script>
<template>
<div class="w-full items-center grid gap-5">
<Tabs class="border rounded" v-model="state.index" :tabs="state.tabs">
<template #tab-panel="{ tab }">
<div class="p-5">{{ tab.content }}</div>
</template>
</Tabs>
<Tabs
class="border rounded"
v-model="state.index"
:tabs="state.tabs"
:vertical="true"
>
<template #tab-panel="{ tab }">
<div class="p-5">{{ tab.content }}</div>
</template>
</Tabs>
</div>
</template>Icons
vue
<script setup lang="ts">
import { reactive } from 'vue'
import { Tabs } from 'frappe-ui'
const state = reactive({
index: 0,
tabs: [
{
label: 'Home',
content:
'Welcome to the home tab. This is a simple example showing how tabs can be paired with icons to give each section a clear, scannable identity.',
icon: 'lucide-house',
},
{
label: 'Messages',
content:
'The messages tab groups all your conversations in one place. Use it to keep track of unread threads and pick up where you left off.',
icon: 'lucide-message-circle',
},
{
label: 'Settings',
content:
'Adjust your preferences in the settings tab — change your theme, manage notifications, and configure how the app behaves.',
icon: 'lucide-settings',
},
],
})
</script>
<template>
<Tabs class="border rounded" v-model="state.index" :tabs="state.tabs">
<template #tab-panel="{ tab }">
<div class="p-5">{{ tab.content }}</div>
</template>
</Tabs>
</template>API Reference
Show types
typescript
import type { Component } from 'vue'
export interface Tab {
/** Text shown for the tab. */
label: string
/**
* Optional icon shown with the label. Pass a `lucide-*` class string for
* the recommended class-based form, or a Vue component for custom icons.
*/
icon?: string | Component
/** Optional route to navigate to when the tab is clicked. */
route?: string
}
export interface TabsProps {
/** Element/component used to render the tab container. */
as?: string
/** List of tabs to render. */
tabs: Tab[]
/** Renders tabs vertically instead of horizontally. */
vertical?: boolean
/** Currently selected tab value. */
modelValue?: string | number
/** Forces layout direction; defaults to `document.documentElement.dir`. */
dir?: 'rtl' | 'ltr'
}
export interface TabsEmits {
/** Fired when the selected tab changes. */
'update:modelValue': [value: string | number]
}as
string
Element/component used to render the tab container.
tabs*
Tab[]
List of tabs to render.
vertical
boolean
Renders tabs vertically instead of horizontally.
modelValue
string | number
Currently selected tab value.
dir
"rtl" | "ltr"
Forces layout direction; defaults to `document.documentElement.dir`.
| Slot | Payload |
|---|---|
tab-item | { tab: { label: string; icon?: string | Component | undefined; route?: string | undefined; }; } Custom renderer for a tab trigger (icon + label / router-link). |
tab-panel | { tab: { label: string; icon?: string | Component | undefined; route?: string | undefined; }; } Content rendered for each tab panel. |
tab-item
{ tab: { label: string; icon?: string | Component | undefined; route?: string | undefined; }; }
Custom renderer for a tab trigger (icon + label / router-link).
tab-panel
{ tab: { label: string; icon?: string | Component | undefined; route?: string | undefined; }; }
Content rendered for each tab panel.
| Event | Payload |
|---|---|
update:modelValue | [value: string | number] Fired when the model value changes. |
update:modelValue
[value: string | number]
Fired when the model value changes.