Tabs
KTabs are horizontal controls that allow users to switch between multiple views within one page.
- Tab 1
- Tab 2
Tab 1 content
<KTabs :tabs="tabs">
<template #tab1>
<p>Tab 1 content</p>
</template>
<template #tab2>
<p>Tab 2 content</p>
</template>
</KTabs>
Props
tabs
Required prop, which is an array of tab objects with the following interface:
interface Tab {
hash: string // has to be unique, corresponds to the panel slot name
title: string
disabled?: boolean
}
- Tab 1
- Tab 2
- Tab 3 (disabled)
Tab 1 content
<KTabs
:tabs="[
{
hash: '#tab1',
title: 'Tab 1'
},
{
hash: '#tab2',
title: 'Tab 2'
},
{
hash: '#tab3',
title: 'Tab 3',
disabled: true
}
]"
>
<template #tab1>
<p>Tab 1 content</p>
</template>
<template #tab2>
<p>Tab 2 content</p>
</template>
<template #tab3>
<p>Tab 3 content</p>
</template>
</KTabs>
v-model
KTabs will set the first tab in the tabs
array as active. You can override this by passing in the hash of any other tab to be used with v-model
.
- Tab 1
- Tab 2
Tab 2 content
<template>
<KTabs v-model="currentTab" :tabs="tabs">
<template #tab1>Tab 1 content</template>
<template #tab2>Tab 2 content</template>
</KTabs>
</template>
<script setup lang="ts">
import type { Tab } from '@kong/kongponents'
const currentTab = ref<string>('#tab2')
const tabs: Tab[] = [
{
hash: '#tab1',
title: 'Tab 1'
},
{
hash: '#tab2',
title: 'Tab 2'
}
]
</script>
If you want to keep your v-model
in sync so that you can programmatically change the active tab after initialization, you also must respond to the @change
emitted event.
- Tab 1
- Tab 2
<KTabs v-model="currentTab" :tabs="tabs" @change="hash => currentTab = hash">
<template #tab1>Tab 1 content</template>
<template #tab2>Tab 2 content</template>
</KTabs>
<KButton @click="currentTab = '#tab1'">Activate Tab 1</KButton>
<KButton @click="currentTab = '#tab2'">Activate Tab 2</KButton>
hidePanels
A boolean
that determines whether all tabs should have corresponding "panel" (the tab content) containers. Defaults to false
.
In some scenarios, you may want to implement the KTabs UI controls without utilizing the corresponding panel containers.
For example, you could set the hidePanels
prop to true
and then your host app could provide custom functionality such as navigating to a different page or router-view
on click.
Here's an example where we display the active tab hash:
- Gateway
- Notifications
- Documentation
- Disabled
Active hash: #gateway
<template>
<KTabs :tabs="tabs" hide-panels @change="tabChange" />
<p>Active hash: {{ currentTab }} </p>
</template>
<script setup lang="ts">
import type { Tab } from '@kong/kongponents'
const tabs: Tab[] = [
{ hash: '#pictures', title: 'Pictures' },
{ hash: '#movies', title: 'Movies' },
{ hash: '#books', title: 'Books' },
]
const currentTab = ref<string>(tabs.value[0].hash)
const tabChange = (hash: string): void => {
currentTab.value = hash
}
</script>
anchorTabindex
This prop allows setting a custom tabindex
for the tab anchor element. It’s useful when passing a custom interactive element, like a link, through the anchor
slot, ensuring that only the slotted element is focusable by resetting the default anchor tabindex
. Default value is 0
.
Dynamic RouterView
Here's an example (code only) of utilizing a dynamic router-view
component within the host app:
<KTabs
hide-panels
:tabs="tabs"
>
<template
v-for="tab in tabs"
:key="`${tab.hash}-anchor`"
#[`${tab.hash}-anchor`]
>
<router-link
:to="{
name: tab.hash.split('?').shift(),
hash: `#${tab.hash.split('?').pop()}`,
}"
>
{{ tab.title }}
</router-link>
</template>
</KTabs>
<router-view v-slot="{ route }">
<h3>Router View content</h3>
<p>{{ route.path }}{{ route.hash }}</p>
</router-view>
Slots
anchor & panel
The tab control defaults to the tab.title
string. You may use the #{tab.hash}-anchor
slot to customize the content of the tab control.
In order provide the tab panel content (when the hidePanels
prop is set to false
) you must slot the content in the named slot, defined by the tab.hash
string, without the #
. For example, if tab.hash
is #notifications
- the panel slot name will be notifications
, like in the example below.
- Gateway
- Notifications3
- Documentation
- Disabled
<KTabs :tabs="tabs">
<template #gateway-anchor>
<KongIcon />
Gateway
</template>
<template #gateway><b>Gateway</b> tab content</template>
<template #notifications-anchor>
<InboxNotificationIcon />
Notifications
<KBadge appearance="decorative">3</KBadge>
</template>
<template #notifications><b>Notifications</b> tab content</template>
<template #docs-anchor>
<BookIcon />
Documentation
</template>
<template #docs><b>Documentation</b> tab content</template>
<template #disabled-anchor>
<KTooltip text="This tab item is disabled.">
<div>Disabled</div>
</KTooltip>
</template>
</KTabs>
Events
change
KTabs emits a @change
event with the new tab hash
when clicked. You can use this to set the router or window hash and in turn use that with v-model
.
<template>
<KTabs
:tabs="tabs"
v-model="$route.hash"
@change="hash => $router.replace({ hash })">
<template #tab1>Tab 1 content</template>
<template #tab2>Tab 2 content</template>
</KTabs>
</template>
<script setup lang="ts">
import type { Tab } from '@kong/kongponents'
// importing $route and $router in your app may vary and is excluded in this example.
const tabs = ref<Tab[]>([
{ hash: '#tab1', title: 'Tab 1' },
{ hash: '#tab2', title: 'Tab 2' },
])
</script>