AK Tabs
ak-ui/tabsFreeComponent
Controlled Vue tabs and segmented mode selection with keyboard navigation.
Install it
npx shadcn@latest add https://ak-ui.yunyoujun.cn/r/tabs.jsonSource
1<script setup lang="ts">2import { computed, nextTick, useId } from 'vue'3import type { AkTabsItem } from './types'45import '@yunyoujun/ak-ui'67const props = defineProps<{8 ariaLabel?: string9 items: AkTabsItem[]10}>()1112const model = defineModel<string>()13const instanceId = useId()14const activeValue = computed(() => model.value ?? props.items[0]?.value ?? '')1516function activate(value: string) {17 model.value = value18}1920function tabId(value: string) {21 return `${instanceId}-tab-${value}`22}2324function panelId(value: string) {25 return `${instanceId}-panel-${value}`26}2728async function onKeydown(index: number, event: KeyboardEvent) {29 const offset = event.key === 'ArrowLeft' ? -1 : event.key === 'ArrowRight' ? 1 : 03031 if (!offset && event.key !== 'Home' && event.key !== 'End')32 return3334 event.preventDefault()35 const nextIndex = event.key === 'Home'36 ? 037 : event.key === 'End'38 ? props.items.length - 139 : (index + offset + props.items.length) % props.items.length40 const nextItem = props.items[nextIndex]4142 activate(nextItem.value)43 await nextTick()44 document.getElementById(tabId(nextItem.value))?.focus()45}46</script>4748<template>49 <section class="ak-tabs" data-slot="ak-tabs">50 <div class="ak-tabs__list" role="tablist" :aria-label="ariaLabel || 'Tabs'">51 <button52 v-for="(item, index) in items"53 :id="tabId(item.value)"54 :key="item.value"55 class="ak-tabs__tab"56 role="tab"57 type="button"58 :aria-controls="panelId(item.value)"59 :aria-selected="activeValue === item.value"60 :tabindex="activeValue === item.value ? 0 : -1"61 @click="activate(item.value)"62 @keydown="onKeydown(index, $event)"63 >64 {{ item.label }}65 </button>66 </div>67 <div68 v-for="item in items"69 v-show="activeValue === item.value"70 :id="panelId(item.value)"71 :key="`${item.value}-panel`"72 class="ak-tabs__panel"73 role="tabpanel"74 :aria-labelledby="tabId(item.value)"75 >76 <span v-if="item.eyebrow" class="ak-tabs__eyebrow">{{ item.eyebrow }}</span>77 <h3 class="ak-tabs__title">{{ item.title }}</h3>78 <p v-if="item.description" class="ak-tabs__description">{{ item.description }}</p>79 <slot :item="item" :name="`panel-${item.value}`" />80 </div>81 </section>82</template>
What it pulls in
npm packages
Files it writes
More from ak-ui
All 7 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| AK Buttonbutton | ak-ui | Components | Free | 1 dep · 3 files | |
| AK Cardcard | ak-ui | Components | Free | 1 dep · 8 files | |
| AK Input Numberinput-number | ak-ui | Components | Free | 1 dep · 2 files | |
| AK Noticenotice | ak-ui | Components | Free | 1 dep · 3 files | |
| AK Progressprogress | ak-ui | Components | Free | 1 dep · 4 files | |
| AK Statusstatus | ak-ui | Components | Free | 1 dep · 4 files |
