Un indicateur (underline ou pill) glisse fluidement vers le tab actif avec transition CSS.
"use client";
import { useRef, useState, useEffect } from "react";
export default function FluidTabs({ tabs }: { tabs: string[] }) {
const [active, setActive] = useState(0);
const [indicator, setIndicator] = useState({ left: 0, width: 0 });
const tabRefs = useRef<(HTMLButtonElement | null)[]>([]);
useEffect(() => {
const el = tabRefs.current[active];
if (el) {
const parent = el.parentElement!.getBoundingClientRect();
const rect = el.getBoundingClientRect();
setIndicator({ left: rect.left - parent.left, width: rect.width });
}
}, [active]);
return (
<div className="relative">
{tabs.map((tab, i) => (
<button key={i} ref={el => { tabRefs.current[i] = el; }}
onClick={() => setActive(i)}>{tab}</button>
))}
<div style={{
position: "absolute", bottom: 0, height: 2,
left: indicator.left, width: indicator.width,
background: "#E1FF6C",
transition: "left 0.3s, width 0.3s",
}} />
</div>
);
}L'indicateur se deplace fluidement vers le tab actif en mesurant la position/largeur de chaque bouton. Style underline par defaut — changez height/borderRadius pour un style pill.