Poora Posted August 5, 2024 Posted August 5, 2024 Hi, How would one go about creating animated tabs like this with GSAP. https://buildui.com/recipes/animated-tabs The above link has been created in framer motion. And I believe framer motions Animate Presence is similar to GSAP FLIP. I've tried doing it with FLIP but haven't had much success. Would love some help pointing me in the right direction. I'm building this in NextJS. Below is my code. The pill element is added/removed behind the text whenever the path changes. export default function NavTextZoop({ text, href, className }) { const path = usePathname(); const state = useRef(null); useGSAP(() => { state.current = Flip.getState(".navWrapper, .pill"); console.log(state.current) }); useEffect(() => { Flip.from(state.current, { duration: 2 }); }, [path]); return ( <Link href={href}> <div className={twMerge( "h-[1.5em] relative px-2.5 py-1 flex justify-center items-center navWrapper", className )} > {href === path && ( <div className="pill bg-white absolute inset-0 h-full rounded-full" ></div> )} <span className="flex h-[1.5em] overflow-hidden items-center justify-center"> <span className="letter inline-block relative leading-[1.5em] h-[1.5em]"> {text} </span> </span> </div> </Link> ); }
Solution Rodrigo Posted August 5, 2024 Solution Posted August 5, 2024 Hi, The demo Jack created in this thread should provide a solid starting point: Also check the demo that uses Flip with reparenting, although check the Flip docs as well since this could be achieved with Flip's fit() method as well: https://gsap.com/docs/v3/Plugins/Flip/static.fit() Hopefully this helps. Happy Tweening!
Poora Posted August 6, 2024 Author Posted August 6, 2024 Thank you. @Rodrigo That was very helpful. I tweaked the solution to be triggered by the path change from the usePathname() hook in NextJS instead of clicking on the links. Here's the code for anyone looking for that solve. const links = [ { href: "/", label: "Portfolio" }, { href: "/about", label: "About" }, { href: "/resume", label: "Resume" }, { href: "/contact", label: "Contact" }, ]; gsap.registerPlugin(useGSAP, Flip); export default function NavTextZoop({ className }) { const path = usePathname(); const [currentPath, setCurrentPath] = useState("/"); const flipState = useRef(); const childRef = useRef(); const container = useRef(); useGSAP( () => { flipState.current = Flip.getState(childRef.current); setCurrentPath(path); }, { scope: container, dependencies: [path] } ); useGSAP( () => { if (!flipState.current || !childRef.current) return; Flip.from(flipState.current, { duration: 0.75, ease: sling, targets: [childRef.current], }); }, { scope: container, dependencies: [currentPath] } ); return ( <span ref={container} className={cn("md:flex gap-1.5 navWrapper", className)} > {links.map((link, i) => ( <Link key={i} href={link.href}> <div className="h-[1.5em] relative px-2.5 py-1 flex justify-center items-center"> {link.href === currentPath && ( <div ref={childRef} data-flip-id="pillId" className="pill bg-white absolute inset-0 h-full rounded-full" ></div> )} <span className="flex h-[1.5em] overflow-hidden items-center justify-center"> <span className="letter inline-block relative leading-[1.5em] h-[1.5em] after:h-[1.5em] after:absolute after:left-0 after:top-full after:content-[attr(data-letter)] z-10 mix-blend-exclusion"> {link.label} </span> </span> </div> </Link> ))} </span> ); } 1
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now