we will explore how to create a section transition using Framer Motion, a popular animation library for React. We will break down the code and explain each component's role in achieving the desired transition effect.
Let's start with the main Home component:
import ContentPageOne from "./components/ContentPageOne";
import ContentPageTwo from "./components/ContentPageTwo";
import SectionTrans from "./components/SectionTrans";
export default function Home() {
return (
<div>
<SectionTrans
sectionOne={<ContentPageOne />}
sectionTwo={<ContentPageTwo />}
/>
</div>
);
}
This component imports two content pages (ContentPageOne and ContentPageTwo) and a SectionTrans component, which will handle the transition between the two pages.
The content pages are simple React components that render some text and an SVG arrow:
import React from "react";
const ContentPageOne = () => {
return (
<div className=" flex items-center justify-center bg-blue-950 text-white w-full h-screen text-4xl ">
<div className="flex items-center gap-6">
<div>scroll down baby</div>
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
className="lucide lucide-arrow-down"
>
<path d="M12 5v14" />
<path d="m19 12-7 7-7-7" />
</svg>
</div>
</div>
</div>
);
};
export default ContentPageOne;
import React from "react";
const ContentPageTwo = () => {
return (
<div className=" flex items-center justify-center bg-white text-black w-full h-screen text-4xl ">
<div className="flex items-center gap-6">
<div>you scrolled enough :3</div>
</div>
</div>
);
};
export default ContentPageTwo;
These components will be used as the content for our section transition.
The SectionTrans component is where the magic happens:
"use client";
import { motion, useScroll, useTransform } from "framer-motion";
import React, { useRef } from "react";
const SectionTrans = ({
sectionOne,
sectionTwo,
}: {
sectionOne: React.ReactNode;
sectionTwo: React.ReactNode;
}) => {
const ref = useRef(null);
const { scrollYProgress } = useScroll({
target: ref,
offset: ["start start", "end end"],
});
// Section One Animation
const scaleONE = useTransform(scrollYProgress, [0, 1], [1, 0.5]);
const opacityONE = useTransform(scrollYProgress, [0, 1], [1, 0.5]);
// Section Two Animation
const scaleTWO = useTransform(scrollYProgress, [0, 1], [0.8, 1]);
const rotateTWO = useTransform(scrollYProgress, [0, 1], [5, 0]);
return (
<main ref={ref} className=" relative h-[200vh]">
<motion.div
style={{
opacity: opacityONE,
scale: scaleONE,
}}
className=" sticky top-0"
>
{sectionOne}
</motion.div>
<motion.div
style={{
scale: scaleTWO,
rotate: rotateTWO,
}}
className=" relative z-10"
>
{sectionTwo}
</motion.div>
</main>
);
};
export default SectionTrans;
This component uses Framer Motion's useScroll and useTransform hooks to create a smooth transition between the two sections. The scrollYProgress variable tracks the scroll position, and the useTransform hook is used to animate the scale, opacity, and rotation of the sections based on the scroll position.