When entering the website, this is the first UI you'll see.

Then, if you scroll down to the very beginning of section B
I expect the section B will become sticky and the currentPercentage state will start increasing from 0% gradually if you scroll.

When the currentPercentage state reach 100%, the sticky effect will no longer apply to sectionB, then you can scroll down to section C or the bottom of the page.
It's kind of like circle-ci homepage
You can try to scroll in this section.

I think there are a few things we need to figure out for the solution
I've tried thinking in both css and javascript way, still cannot find the solution
I've also done lots of research for this problem for a few days but still not figuring it out.
I believe a lots of developers would like to know how to do this kind of effect in their frontend, and it will be beneficial for other developers to have quicker solution to deal with this kind of UX in the future, since from what I've noticed no one has mentioned this kind of UX handling.
I would be appreciated if someone can answer this question with an example, for the reference for other developers.
App.js
import "./styles.css";
import "bootstrap/dist/css/bootstrap.min.css";
import ProgressBar from "react-bootstrap/ProgressBar";
import { useState } from "react";
export default function App() {
const [currentProgress, setCurrentProgress] = useState(100);
return (
<div className="App">
<div className="sectionA">Section A</div>
<div className="sectionB">
Section B
<ProgressBar
now={currentProgress}
label={`${currentProgress}%`}
style={{ marginBottom: "16px" }}
/>
</div>
<div className="sectionC">Section C</div>
</div>
);
}
Codesandbox
https://codesandbox.io/s/mutable-fire-sz19b?file=/src/App.js:0-619
Update 1
I updated the code and can be able to make container B sticky, but dont know how to continue for the UX
App.js
import "./styles.css";
import "bootstrap/dist/css/bootstrap.min.css";
import ProgressBar from "react-bootstrap/ProgressBar";
import { useState } from "react";
export default function App() {
const [currentProgress, setCurrentProgress] = useState(3);
return (
<div className="App">
<div className="sectionA">Section A</div>
<div style={{ position: "sticky", top: 0 }}>
<div className="sectionB">
Section B
<ProgressBar
now={currentProgress}
label={`${currentProgress}%`}
style={{ marginBottom: "16px" }}
/>
</div>
<div className="sectionC">Section C</div>
</div>
<div style={{ minHeight: "400vh", maxHeight: "calc(200vh - 466px)" }} />
</div>
);
}
Codesandbox
https://codesandbox.io/s/elated-hawking-n3rvw?file=/src/App.js:0-778
Update 2
Added library react-scroll-percentage to scroll to update
currentProgress
However, when the whole containerB exposed in the viewport, the currentProgress will start updating, which is not what I want

What I want is when SectionB reach the top of the viewport, the scrolling will make user feel sticky and then currentProgress will start updating from 0%
App.js
import "./styles.css";
import "bootstrap/dist/css/bootstrap.min.css";
import React, { useState, useEffect } from "react";
import { useScrollPercentage } from "react-scroll-percentage";
import ProgressBar from "react-bootstrap/ProgressBar";
export default function App() {
const [currentProgress, setCurrentProgress] = useState(0);
const [ref, percentage] = useScrollPercentage({
threshold: 1.0
});
useEffect(() => {
setCurrentProgress(percentage * 100);
}, [percentage]);
return (
<div className="App">
<div className="sectionA">Section A</div>
<div style={{ position: "sticky", top: 0 }}>
<div className="sectionB" ref={ref}>
Section B
<ProgressBar
now={currentProgress}
label={`(${currentProgress})%`}
style={{ marginBottom: "16px" }}
/>
</div>
<div className="sectionC">Section C</div>
</div>
<div style={{ minHeight: "400vh", maxHeight: "calc(200vh - 466px)" }} />
</div>
);
}
Codesandbox
https://codesandbox.io/s/elated-hawking-n3rvw?file=/src/App.js:0-1029
You need to listen to scroll events, check scrollTop of the scrolling element, and decide what the css and currentProgress need to be. This is easiest when the height of each section is known and constant. The outer element also needs a large predetermined height, to leave room for scrolling.
The code might just be
if (scrollTop > heightofSectionA) {
//set sectionB css to {position: fixed, top: 0, ...}
currentProgress = (scrollTop-heightofSectionA)/lengthofSectionB*100
} else {
//set sectionB css to {position: static}
currentProgress = 0
}
There is a number of ways the html and css could look. With position: sticky you might not need to change css at all. But as long as you know what the css at any stage of the scroll should look like, you should have no problems switching between them.