Animated Tabs
July 18, 2025
Here is a simple tabs animation using motion and shadcn tabs, it includes mix-blend-exclusion which causes the text color to invert only where the indicator and text overlap.
import * as TabsPrimitive from '@radix-ui/react-tabs'; import { motion } from 'motion/react'; import { cn } from '@/core/lib/cn'; interface AnimatedTabsTriggerProps extends React.ComponentProps<typeof TabsPrimitive.Trigger> { isActive?: boolean; activeProps?: React.ComponentProps<typeof motion.span>; layoutId: string; durationMultiplier?: number; } const AnimatedTabsTrigger = ({ className, children, isActive, activeProps, layoutId, durationMultiplier = 1, ...props }: AnimatedTabsTriggerProps) => ( <TabsPrimitive.Trigger className={cn( 'group ring-offset-background text-primary focus-visible:ring-ring relative inline-flex items-center justify-center rounded-sm px-3 py-1.5 text-sm font-medium whitespace-nowrap transition-all focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50', className )} {...props} > {children} {isActive && ( <motion.span layoutId={layoutId} className={cn("bg-secondary dark:bg-secondary-foreground absolute inset-0 bottom-0 z-10 mix-blend-difference", activeProps?.className)} style={{ borderRadius: 9999 }} transition={{ type: 'spring', bounce: 0.2, duration: 0.8 / durationMultiplier, }} {...activeProps} /> )} </TabsPrimitive.Trigger> );