This example uses the useMotionValue() and useTransform() hooks to change the width of the bar at the bottom.
Here, we have a scrollY Motion value that we pass to the draggable div’s y.
This way, the scrollY Motion value will update whenever you drag the div, and we can change it with useTransform()to another Motion value that changes the width of the bottom div.
const items = [0, 1, 2, 3, 4];
const height = 70;
const padding = 10;
const size = 150;
export function Example() {
const scrollY = useMotionValue(0);
const width = useTransform(
scrollY,
[0, -getHeight(items) + size],
["calc(0% - 0px)", "calc(100% - 40px)"]
);
return (
<>
<motion.div
style={{
width: 150,
height: 150,
borderRadius: 30,
overflow: "hidden",
position: "relative",
transform: "translateZ(0)",
}}
>
<motion.div
style={{
width: 150,
height: getHeight(items),
y: scrollY
}}
drag="y"
dragConstraints={{
top: -getHeight(items) + size,
bottom: 0
}}
>
{items.map((index) => {
return (
<motion.div
style={{
width: 150,
height: height,
borderRadius: 20,
backgroundColor: "#fff",
position: "absolute",
top: (height + padding) * index
}}
key={index}
/>
);
})}
</motion.div>
</motion.div>
<motion.div
style={{
width,
height: 6,
borderRadius: 3,
backgroundColor: "#fff",
position: "absolute",
bottom: 20,
left: 20
}}
/>
</>
);
}
function getHeight(items) {
const totalHeight = items.length * height;
const totalPadding = (items.length - 1) * padding;
const totalScroll = totalHeight + totalPadding;
return totalScroll;
}
We’re using CSS’s calc() to set the value to a maximum of the available width (100%) minus two times 20px for the margins left and right.