Animated tabs

Using Framer Motion we can create this nice transition effect, making the tabs stand out from your ordinary component

Pill selector

Underscore selector

'use client'
import { motion } from 'framer-motion'
import React from 'react'
import { cn } from '@/utils'
type Tab = {
id: string
label: string
}
type TabsProps = {
id: string
tabs: Tab[]
type?: 'pill' | 'underscore'
}
export function Tabs({ id, tabs, type = 'pill' }: TabsProps) {
const [activeTab, setActiveTab] = React.useState<string>(tabs[0].id)
return (
<div className={'flex flex-wrap items-center gap-1'}>
{tabs.map(tab => (
<button
key={tab.id}
onClick={() => setActiveTab(tab.id)}
style={{
WebkitTapHighlightColor: 'transparent',
}}
className={cn(
'relative rounded-full px-2 py-1 text-sm font-medium text-black transition focus-visible:outline-2',
{ 'hover:text-black/50': activeTab !== tab.id }
)}>
{activeTab === tab.id && (
<motion.span
layoutId={id}
className={cn('absolute z-10 rounded-full', {
'inset-0 bg-white mix-blend-exclusion': type === 'pill',
'bottom-0 left-2 right-2 h-1 bg-black': type === 'underscore',
})}
transition={{
type: 'spring',
bounce: 0.15,
duration: 0.5,
}}
/>
)}
{tab.label}
</button>
))}
</div>
)
}