Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 2 additions & 1 deletion docs/content/3.components/tabs.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ Use the `items` prop as an array of objects with the following properties:
- `label?: string`{lang="ts-type"}
- `icon?: string`{lang="ts-type"}
- `avatar?: AvatarProps`{lang="ts-type"}
- `badge?: string | number | BadgeProps`{lang="ts-type"}
- `content?: string`{lang="ts-type"}
- `value?: string | number`{lang="ts-type"}
- `disabled?: boolean`{lang="ts-type"}
- [`slot?: string`{lang="ts-type"}](#with-custom-slot)
- `class?: any`{lang="ts-type"}
- `ui?: { trigger?: ClassNameValue, leadingIcon?: ClassNameValue, leadingAvatar?: ClassNameValue, label?: ClassNameValue, content?: ClassNameValue }`{lang="ts-type"}
- `ui?: { trigger?: ClassNameValue, leadingIcon?: ClassNameValue, leadingAvatar?: ClassNameValue, label?: ClassNameValue, content?: ClassNameValue, trailingBadge?: ClassNameValue, trailingBadgeSize?: ClassNameValue }`{lang="ts-type"}

::component-code
---
Expand Down
3 changes: 2 additions & 1 deletion playground/app/pages/components/tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ const items = [{
label: 'Tab3',
icon: 'i-lucide-bell',
content: 'Finally, this is the content for Tab3',
slot: 'custom' as const
slot: 'custom' as const,
badge: '300'
}]
</script>

Expand Down
20 changes: 17 additions & 3 deletions src/runtime/components/Tabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import type { TabsRootProps, TabsRootEmits } from 'reka-ui'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/ui/tabs'
import type { AvatarProps } from '../types'
import type { AvatarProps, BadgeProps } from '../types'
import type { DynamicSlots, ComponentConfig } from '../types/utils'

type Tabs = ComponentConfig<typeof theme, AppConfig, 'tabs'>
Expand All @@ -15,13 +15,18 @@ export interface TabsItem {
*/
icon?: string
avatar?: AvatarProps
/**
* Display a badge on the item.
* `{ size: 'sm', color: 'neutral', variant: 'outline' }`{lang="ts-type"}
*/
badge?: string | number | BadgeProps
slot?: string
content?: string
/** A unique value for the tab item. Defaults to the index. */
value?: string | number
disabled?: boolean
class?: any
ui?: Pick<Tabs['slots'], 'trigger' | 'leadingIcon' | 'leadingAvatar' | 'label' | 'content'>
ui?: Pick<Tabs['slots'], 'trigger' | 'leadingIcon' | 'leadingAvatar' | 'label' | 'content' | 'trailingBadge' | 'trailingBadgeSize'>
[key: string]: any
}

Expand Down Expand Up @@ -141,7 +146,16 @@ defineExpose({
<slot :item="item" :index="index">{{ get(item, props.labelKey as string) }}</slot>
</span>

<slot name="trailing" :item="item" :index="index" />
<slot name="trailing" :item="item" :index="index">
<UBadge
v-if="item.badge"
Copy link
Contributor

@MickL MickL Jul 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe v-if="item.badge !== undefined" ? Because if badge is 0 it doesnt get displayed even tho it may be intended to display a zero.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MickL Indeed! Fixed in: b22891a

color="neutral"
variant="outline"
:size="((item.ui?.trailingBadgeSize || props.ui?.trailingBadgeSize || ui.trailingBadgeSize()) as BadgeProps['size'])"
v-bind="(typeof item.badge === 'string' || typeof item.badge === 'number') ? { label: item.badge } : item.badge"
:class="ui.trailingBadge({ class: [props.ui?.trailingBadge, item.ui?.trailingBadge] })"
/>
</slot>
</TabsTrigger>

<slot name="list-trailing" />
Expand Down
2 changes: 2 additions & 0 deletions src/theme/tabs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ export default (options: Required<ModuleOptions>) => ({
list: 'relative flex p-1 group',
indicator: 'absolute transition-[translate,width] duration-200',
trigger: ['group relative inline-flex items-center min-w-0 data-[state=inactive]:text-muted hover:data-[state=inactive]:not-disabled:text-default font-medium rounded-md disabled:cursor-not-allowed disabled:opacity-75', options.theme.transitions && 'transition-colors'],
trailingBadge: 'shrink-0',
trailingBadgeSize: 'sm',
content: 'focus:outline-none w-full',
leadingIcon: 'shrink-0',
leadingAvatar: 'shrink-0',
Expand Down
3 changes: 2 additions & 1 deletion test/components/Tabs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ describe('Tabs', () => {
label: 'Tab3',
icon: 'i-lucide-bell',
content: 'Finally, this is the content for Tab3',
slot: 'custom'
slot: 'custom',
badge: 'badge'
}]

const props = { items }
Expand Down
183 changes: 160 additions & 23 deletions test/components/__snapshots__/Tabs-vue.spec.ts.snap

Large diffs are not rendered by default.

183 changes: 160 additions & 23 deletions test/components/__snapshots__/Tabs.spec.ts.snap

Large diffs are not rendered by default.