registry:component

Motion Tabs

v1.0.0ga

Tabs primitive with animated active-state transitions.

Registry Endpoint
Open JSON

https://registry.aavya.com/r/ui-motion-tabs.json

npx shadcn@latest add https://registry.aavya.com/r/ui-motion-tabs.json

Live Preview
Motion tabs overview content.
Motion tabs activity content.
Usage Snippet
import MotionTabs from '@/components/ui/motion-tabs.tsx'

export default function Example() {
  return (
    <div className="p-6">
      <MotionTabs />
    </div>
  )
}
Source Preview
'use client'

import * as React from 'react'

import { motion, type Transition, type HTMLMotionProps } from 'motion/react'

import { cn } from '@/lib/utils'
import { MotionHighlight, MotionHighlightItem } from '@/components/ui/motion-highlight'

type TabsContextType<T extends string> = {
  activeValue: T
  handleValueChange: (value: T) => void
  registerTrigger: (value: T, node: HTMLElement | null) => void
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const TabsContext = React.createContext<TabsContextType<any> | undefined>(undefined)

function useTabs<T extends string = string>(): TabsContextType<T> {
  const context = React.useContext(TabsContext)

  if (!context) {
    throw new Error('useTabs must be used within a TabsProvider')
  }

  return context
}

type BaseTabsProps = React.ComponentProps<'div'> & {
  children: React.ReactNode
}

type UnControlledTabsProps<T extends string = string> = BaseTabsProps & {
  defaultValue?: T
  value?: never
  onValueChange?: never
}

type ControlledTabsProps<T extends string = string> = BaseTabsProps & {
  value: T
  onValueChange?: (value: T) => void
  defaultValue?: never
}

type TabsProps<T extends string = string> = UnControlledTabsProps<T> | ControlledTabsProps<T>

function Tabs<T extends string = string>({
  defaultValue,
  value,
  onValueChange,
  children,
  className,
  ...props
}: TabsProps<T>) {
  const [ac