{
  "$schema": "https://shadcn-vue.com/schema/registry-item.json",
  "name": "tabs",
  "title": "Tabs",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-vue/components/tabs/Tabs.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, provide } from 'vue'\nimport type { TabsRootEmits, TabsRootProps } from 'reka-ui'\nimport type { HTMLAttributes } from 'vue'\nimport { reactiveOmit } from '@vueuse/core'\nimport { TabsRoot, useForwardPropsEmits } from 'reka-ui'\nimport { cn } from '@/lib/utils'\n\nconst props = defineProps<\n  TabsRootProps & {\n    class?: HTMLAttributes['class']\n    orientation?: 'horizontal' | 'vertical'\n  }\n>()\nconst emits = defineEmits<TabsRootEmits>()\n\nconst delegatedProps = reactiveOmit(props, 'class', 'orientation')\nconst forwarded = useForwardPropsEmits(delegatedProps, emits)\n\n// Make orientation reachable from descendants without each consumer having to\n// pass it manually. TabsList / TabsTrigger inject this to apply variant CSS.\nprovide(\n  Symbol.for('tabsOrientation'),\n  computed(() => props.orientation ?? 'horizontal'),\n)\n</script>\n\n<template>\n  <TabsRoot\n    data-uipkge\n    data-slot=\"tabs\"\n    :data-orientation=\"orientation ?? 'horizontal'\"\n    :orientation=\"orientation ?? 'horizontal'\"\n    v-bind=\"forwarded\"\n    :class=\"cn('flex w-full', orientation === 'vertical' ? 'flex-row gap-4' : 'flex-col gap-2', props.class)\"\n  >\n    <slot />\n  </TabsRoot>\n</template>\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/tabs/Tabs.vue"
    },
    {
      "path": "packages/registry-vue/components/tabs/TabsContent.vue",
      "content": "<script setup lang=\"ts\">\nimport type { HTMLAttributes } from 'vue'\nimport { TabsContent, type TabsContentProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\n\ninterface Props {\n  class?: HTMLAttributes['class']\n  value: string\n  forceMount?: boolean\n}\n\nconst props = defineProps<Props>()\n</script>\n\n<template>\n  <TabsContent\n    v-slot=\"slotProps\"\n    :value=\"props.value\"\n    :force-mount=\"props.forceMount\"\n    :class=\"\n      cn(\n        'ring-offset-background focus-visible:border-ring focus-visible:ring-ring/50 flex-1 focus-visible:ring-2 focus-visible:ring-[3px] focus-visible:outline-none',\n        props.class,\n      )\n    \"\n    data-uipkge\n    data-slot=\"tabs-content\"\n  >\n    <slot v-bind=\"slotProps\" />\n  </TabsContent>\n</template>\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/tabs/TabsContent.vue"
    },
    {
      "path": "packages/registry-vue/components/tabs/TabsList.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, inject } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport { reactiveOmit } from '@vueuse/core'\nimport { TabsList, useForwardProps } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { tabsListVariants } from './tabs.variants'\n\n// Inlined unions: SFC compiler can't extract runtime props from\n// indexed-access types or reka-ui's TabsListProps.\nconst props = defineProps<{\n  class?: HTMLAttributes['class']\n  variant?: 'segmented' | 'pill' | 'underline'\n  orientation?: 'horizontal' | 'vertical'\n  asChild?: boolean\n  as?: string | object\n  loop?: boolean\n}>()\n\nconst delegatedProps = reactiveOmit(props, 'class', 'variant', 'orientation')\nconst forwarded = useForwardProps(delegatedProps)\n\n// Inherit orientation from <Tabs> when not set explicitly. Provided as a\n// computed ref by Tabs.vue so updates propagate.\nconst tabsOrientation = inject<{ value: 'horizontal' | 'vertical' } | 'horizontal' | 'vertical'>(\n  Symbol.for('tabsOrientation'),\n  'horizontal',\n)\nconst effectiveOrientation = computed(() => {\n  if (props.orientation) return props.orientation\n  return typeof tabsOrientation === 'string' ? tabsOrientation : tabsOrientation.value\n})\n</script>\n\n<template>\n  <TabsList\n    data-uipkge\n    data-slot=\"tabs-list\"\n    v-bind=\"forwarded\"\n    :class=\"cn(tabsListVariants({ variant, orientation: effectiveOrientation }), props.class)\"\n  >\n    <slot />\n  </TabsList>\n</template>\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/tabs/TabsList.vue"
    },
    {
      "path": "packages/registry-vue/components/tabs/TabsTrigger.vue",
      "content": "<script setup lang=\"ts\">\nimport { computed, inject } from 'vue'\nimport type { HTMLAttributes } from 'vue'\nimport { TabsTrigger } from 'reka-ui'\nimport { cn } from '@/lib/utils'\nimport { tabsTriggerVariants } from './tabs.variants'\n\n// Inlined unions: SFC compiler can't extract runtime props from\n// indexed-access types like TabsTriggerVariants['size'].\nconst props = withDefaults(\n  defineProps<{\n    class?: HTMLAttributes['class']\n    size?: 'default' | 'sm' | 'lg'\n    variant?: 'segmented' | 'pill' | 'underline'\n    orientation?: 'horizontal' | 'vertical'\n    value: string\n    disabled?: boolean\n  }>(),\n  {\n    disabled: false,\n  },\n)\n\nconst tabsOrientation = inject<{ value: 'horizontal' | 'vertical' } | 'horizontal' | 'vertical'>(\n  Symbol.for('tabsOrientation'),\n  'horizontal',\n)\nconst effectiveOrientation = computed(() => {\n  if (props.orientation) return props.orientation\n  return typeof tabsOrientation === 'string' ? tabsOrientation : tabsOrientation.value\n})\n</script>\n\n<template>\n  <TabsTrigger\n    v-slot=\"slotProps\"\n    :value=\"props.value\"\n    :disabled=\"props.disabled\"\n    data-uipkge\n    data-slot=\"tabs-trigger\"\n    :class=\"\n      cn(\n        tabsTriggerVariants({\n          size: props.size,\n          variant: props.variant,\n          orientation: effectiveOrientation,\n        }),\n        props.class,\n      )\n    \"\n  >\n    <slot v-bind=\"slotProps\" />\n  </TabsTrigger>\n</template>\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/tabs/TabsTrigger.vue"
    },
    {
      "path": "packages/registry-vue/components/tabs/tabs.variants.ts",
      "content": "import type { VariantProps } from 'class-variance-authority'\nimport { cva } from 'class-variance-authority'\n\n/**\n * Variant definitions live in their own file (rather than the package\n * `index.ts`) so consuming Vue SFCs can import without creating a circular\n * dependency through the index. See card.variants.ts for the canonical\n * example + the SSR symptom that motivated the split.\n */\n\nexport const tabsListVariants = cva('inline-flex items-stretch text-muted-foreground', {\n  variants: {\n    variant: {\n      // Solid muted track with rounded inset triggers — the default look.\n      segmented: 'gap-1 rounded-md bg-muted p-1',\n      // Transparent track with rounded-full pill triggers.\n      pill: 'gap-2 bg-transparent p-0',\n      // Bottom-border bar (horizontal) or right-border bar (vertical), with\n      // an underline on the active trigger.\n      underline: 'gap-0 bg-transparent p-0',\n    },\n    orientation: {\n      horizontal: 'flex-row',\n      vertical: 'h-auto flex-col items-stretch',\n    },\n  },\n  compoundVariants: [\n    {\n      variant: 'underline',\n      orientation: 'horizontal',\n      class: 'w-full justify-start border-b border-border',\n    },\n    {\n      variant: 'underline',\n      orientation: 'vertical',\n      class: 'border-r border-border',\n    },\n  ],\n  defaultVariants: {\n    variant: 'segmented',\n    orientation: 'horizontal',\n  },\n})\n\nexport const tabsTriggerVariants = cva(\n  'inline-flex items-center justify-center gap-1.5 whitespace-nowrap font-medium ring-offset-background transition-[color,background-color,box-shadow,border-color] duration-150 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50',\n  {\n    variants: {\n      variant: {\n        segmented:\n          'rounded-sm data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-xs',\n        pill: 'rounded-full border border-border bg-transparent data-[state=active]:bg-primary data-[state=active]:text-primary-foreground data-[state=active]:border-primary',\n        underline:\n          'rounded-none border-b-2 border-transparent -mb-px data-[state=active]:border-foreground data-[state=active]:text-foreground',\n      },\n      size: {\n        default: 'h-9 px-3 text-sm',\n        sm: 'h-8 px-2.5 text-xs',\n        lg: 'h-10 px-4 text-sm',\n      },\n      orientation: {\n        horizontal: '',\n        vertical: 'w-full justify-start',\n      },\n    },\n    compoundVariants: [\n      {\n        variant: 'underline',\n        orientation: 'vertical',\n        class: 'border-b-0 border-r-2 -mr-px',\n      },\n    ],\n    defaultVariants: {\n      variant: 'segmented',\n      size: 'default',\n      orientation: 'horizontal',\n    },\n  },\n)\n\nexport type TabsListVariants = VariantProps<typeof tabsListVariants>\n\nexport type TabsTriggerVariants = VariantProps<typeof tabsTriggerVariants>\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/tabs/tabs.variants.ts"
    },
    {
      "path": "packages/registry-vue/components/tabs/index.ts",
      "content": "export { default as Tabs } from './Tabs.vue'\nexport { default as TabsContent } from './TabsContent.vue'\nexport { default as TabsList } from './TabsList.vue'\nexport { default as TabsTrigger } from './TabsTrigger.vue'\n\n// Re-export variant API from the sibling file (kept separate to avoid the\n// Component.vue <-> index.ts circular import that broke dev SSR for Card).\nexport { tabsListVariants, tabsTriggerVariants, type TabsListVariants, type TabsTriggerVariants } from './tabs.variants'\n",
      "type": "registry:ui",
      "target": "~/app/components/ui/tabs/index.ts"
    }
  ],
  "dependencies": [
    "@vueuse/core",
    "class-variance-authority",
    "reka-ui"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Horizontal tab navigation with content panels — pick one panel at a time. Underline or pills variants. Built on reka-ui with full keyboard navigation.",
  "categories": [
    "navigation"
  ]
}