Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<script setup lang="ts">
import type { TabsItem } from '@nuxt/ui'

const items: TabsItem[] = [
{ label: 'Overview', icon: 'i-lucide-layout-dashboard', content: 'Overview content' },
{ label: 'Activity', icon: 'i-lucide-activity', content: 'Activity content' },
{ label: 'Settings', icon: 'i-lucide-settings', content: 'Settings content' },
{ label: 'Members', icon: 'i-lucide-users', content: 'Members content' },
{ label: 'Billing', icon: 'i-lucide-credit-card', content: 'Billing content' },
{ label: 'Integrations', icon: 'i-lucide-plug', content: 'Integrations content' },
{ label: 'Notifications', icon: 'i-lucide-bell', content: 'Notifications content' },
{ label: 'Security', icon: 'i-lucide-shield', content: 'Security content' }
]
</script>

<template>
<UTabs
overflow="collapse"
:items="items"
class="w-96"
/>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
import type { TabsItem } from '@nuxt/ui'

const items: TabsItem[] = [
{ label: 'Overview', icon: 'i-lucide-layout-dashboard', content: 'Overview content' },
{ label: 'Activity', icon: 'i-lucide-activity', content: 'Activity content' },
{ label: 'Settings', icon: 'i-lucide-settings', content: 'Settings content' },
{ label: 'Members', icon: 'i-lucide-users', content: 'Members content' },
{ label: 'Billing', icon: 'i-lucide-credit-card', content: 'Billing content' },
{ label: 'Integrations', icon: 'i-lucide-plug', content: 'Integrations content' },
{ label: 'Notifications', icon: 'i-lucide-bell', content: 'Notifications content' },
{ label: 'Security', icon: 'i-lucide-shield', content: 'Security content' }
]
</script>

<template>
<UTabs
overflow="scroll"
:content="false"
:items="items"
class="w-96"
/>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
import type { TabsItem } from '@nuxt/ui'

const items: TabsItem[] = [
{ label: 'Overview', icon: 'i-lucide-layout-dashboard', content: 'Overview content' },
{ label: 'Activity', icon: 'i-lucide-activity', content: 'Activity content' },
{ label: 'Settings', icon: 'i-lucide-settings', content: 'Settings content' },
{ label: 'Members', icon: 'i-lucide-users', content: 'Members content' },
{ label: 'Billing', icon: 'i-lucide-credit-card', content: 'Billing content' },
{ label: 'Integrations', icon: 'i-lucide-plug', content: 'Integrations content' },
{ label: 'Notifications', icon: 'i-lucide-bell', content: 'Notifications content' },
{ label: 'Security', icon: 'i-lucide-shield', content: 'Security content' }
]
</script>

<template>
<UTabs
overflow="wrap"
:content="false"
:items="items"
class="w-96"
/>
</template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<script setup lang="ts">
import type { TabsItem } from '@nuxt/ui'

const items: TabsItem[] = [
{
label: 'Home',
icon: 'i-lucide-house',
content: 'Home content'
},
{
label: 'Activity',
icon: 'i-lucide-activity',
content: 'Activity content'
},
{
label: 'Settings',
icon: 'i-lucide-settings',
content: 'Settings content'
},
{
label: 'Profile',
icon: 'i-lucide-user',
content: 'Profile content'
}
]
</script>

<template>
<UTabs
trigger-orientation="vertical"
variant="link"
color="neutral"
:items="items"
:ui="{
root: 'w-full border-t border-default py-2',
list: 'justify-around w-full',
trigger: 'grow-0'
}"
class="w-full"
/>
</template>
132 changes: 132 additions & 0 deletions docs/content/docs/2.components/tabs.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,73 @@ props:
---
::

### Trigger orientation :badge{label="Soon" class="align-text-top"}

Use the `trigger-orientation` prop to stack the icon or avatar on top of the label inside each tab trigger. Defaults to `horizontal`.

::component-code
---
ignore:
- content
- items
- class
external:
- items
externalTypes:
- TabsItem[]
props:
triggerOrientation: vertical
variant: link
color: neutral
content: false
items:
- label: Account
icon: 'i-lucide-user'
- label: Password
icon: 'i-lucide-lock'
class: 'w-full'
---
::

### Overflow :badge{label="Soon" class="align-text-top"}

Use the `overflow` prop to control how the tab list handles items that don't fit in the available space:

- `scroll`{lang="ts-type"} enables scrolling along the list axis.
- `wrap`{lang="ts-type"} allows tabs to wrap onto multiple lines.
- `collapse`{lang="ts-type"} hides overflowing tabs behind a **More** dropdown.

When omitted, no overflow handling is applied.

#### Scroll

::component-example
---
collapse: true
name: 'tabs-overflow-scroll-example'
---
::

#### Wrap

::component-example
---
collapse: true
name: 'tabs-overflow-wrap-example'
---
::

#### Collapse

Use the `more-label` and `more-icon` props to customize the overflow trigger. You can also use the `#more` slot to fully customize it.

::component-example
---
collapse: true
name: 'tabs-overflow-collapse-example'
---
::
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Outdated

## Examples

### Control active item
Expand All @@ -241,6 +308,17 @@ Use the `#content` slot to customize the content of each item.

:component-example{name="tabs-content-slot-example"}

### With bottom tab bar :badge{label="Soon" class="align-text-top"}

Combine `trigger-orientation="vertical"` with the `ui` prop to create a mobile-style bottom tab bar with icons and small labels.

::component-example
---
collapse: true
name: 'tabs-trigger-orientation-example'
---
::

### With custom slot

Use the `slot` property to customize a specific item.
Expand All @@ -256,6 +334,60 @@ name: 'tabs-custom-slot-example'
---
::

### `class` prop

Use the `class` prop to override the base styles of the Tabs.

::component-code
---
ignore:
- items
- class
external:
- items
externalTypes:
- TabsItem[]
props:
items:
- label: Account
icon: 'i-lucide-user'
content: 'This is the account content.'
- label: Password
icon: 'i-lucide-lock'
content: 'This is the password content.'
class: 'w-96'
---
::

### `ui` prop

Use the `ui` prop to override the slot styles of the Tabs.

::component-code
---
prettier: true
ignore:
- ui
- items
- class
external:
- items
externalTypes:
- TabsItem[]
props:
content: false
items:
- label: Account
icon: 'i-lucide-user'
- label: Password
icon: 'i-lucide-lock'
class: 'w-full'
ui:
list: 'bg-default ring ring-default'
trigger: 'data-[state=active]:text-primary'
---
::

## API

### Props
Expand Down
32 changes: 32 additions & 0 deletions playgrounds/nuxt/app/pages/components/tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import theme from '#build/ui/tabs'
const colors = Object.keys(theme.variants.color)
const variants = Object.keys(theme.variants.variant)
const orientations = Object.keys(theme.variants.orientation)
const triggerOrientations = Object.keys(theme.variants.triggerOrientation)
const overflows = ['none', ...Object.keys(theme.variants.overflow)]
const sizes = Object.keys(theme.variants.size)

const attrs = reactive({
Expand All @@ -13,6 +15,8 @@ const attrs = reactive({
})

const orientation = ref('horizontal' as keyof typeof theme.variants.orientation)
const triggerOrientation = ref('horizontal' as keyof typeof theme.variants.triggerOrientation)
const overflow = ref<'none' | keyof typeof theme.variants.overflow>('none')

const items = [{
label: 'Tab1',
Expand All @@ -31,6 +35,21 @@ const items = [{
slot: 'custom' as const,
badge: '300'
}]

const manyItems = [
{ label: 'Overview', icon: 'i-lucide-layout-dashboard', content: 'Overview content' },
{ label: 'Activity', icon: 'i-lucide-activity', content: 'Activity content' },
{ label: 'Settings', icon: 'i-lucide-settings', content: 'Settings content' },
{ label: 'Members', icon: 'i-lucide-users', content: 'Members content' },
{ label: 'Billing', icon: 'i-lucide-credit-card', content: 'Billing content' },
{ label: 'Integrations', icon: 'i-lucide-plug', content: 'Integrations content' },
{ label: 'Notifications', icon: 'i-lucide-bell', content: 'Notifications content' },
{ label: 'Security', icon: 'i-lucide-shield', content: 'Security content' },
{ label: 'API Keys', icon: 'i-lucide-key', content: 'API Keys content' },
{ label: 'Logs', icon: 'i-lucide-scroll-text', content: 'Logs content' }
]

const overflowProp = computed(() => overflow.value === 'none' ? undefined : overflow.value)
</script>

<template>
Expand All @@ -39,18 +58,22 @@ const items = [{
<USelect v-model="attrs.variant" :items="variants" placeholder="Variant" multiple />
<USelect v-model="attrs.size" :items="sizes" placeholder="Size" multiple />
<USelect v-model="orientation" :items="orientations" placeholder="Orientation" />
<USelect v-model="triggerOrientation" :items="triggerOrientations" placeholder="Trigger orientation" />
<USelect v-model="overflow" :items="overflows" placeholder="Overflow" />
</Navbar>

<Matrix v-slot="props" :attrs="attrs" container-class="gap-4">
<UTabs
:orientation="orientation"
:trigger-orientation="triggerOrientation"
:items="[{ label: 'Monthly' }, { label: 'Yearly' }]"
:content="false"
v-bind="props"
/>

<UTabs
:orientation="orientation"
:trigger-orientation="triggerOrientation"
:items="items"
class="w-80"
v-bind="props"
Expand All @@ -59,5 +82,14 @@ const items = [{
<span class="text-muted">Custom: {{ item.content }}</span>
</template>
</UTabs>

<UTabs
:orientation="orientation"
:trigger-orientation="triggerOrientation"
:overflow="overflowProp"
:items="manyItems"
:class="orientation === 'vertical' ? 'h-80' : 'w-96'"
v-bind="props"
/>
</Matrix>
</template>
Loading
Loading