My current project involves implementing a sticky header in a React application using the Carbon framework. The goal is to have a sticky header with a bottom border when users scroll up, providing context for their viewing experience. However, when they scroll back down to the original page display, the header should no longer be sticky and shouldn't have a bottom border. I've utilized the Intersection Observer API for this functionality but have been encountering a flickering issue during scrolling. To manage this, I apply CSS classes based on the sticky state using debounced state updates.
If you have any recommendations or advice on how I can achieve the desired behavior, I would greatly appreciate it. You can view a video demonstration of the issue here.
You can also access the reproduction example on CodeSandbox (codesnadbox.io)
const [showStickyHeader, setShowStickyHeader] = useState(false);
const observer = useRef(null);
const debouncedSetShowStickyHeader = useRef(
debounce((value) => setShowStickyHeader(value), 50)
).current;
const stickyMenuHeaderRef = useCallback(
(node) => {
if (observer.current) {
observer.current.disconnect();
}
if (node) {
observer.current = new IntersectionObserver(
([entry]) => {
const shouldStick = entry.intersectionRatio < 0.95;
debouncedSetShowStickyHeader(shouldStick);
},
{
threshold: [0, 0.95, 1],
rootMargin: '0px 0px -5px 0px',
}
);
observer.current.observe(node);
}
return () => {
if (observer.current) {
observer.current.disconnect();
}
debouncedSetShowStickyHeader.cancel();
};
},
[debouncedSetShowStickyHeader]
);
.resultsHeader {
padding: var(--spacing-03) 0;
z-index: 10;
background-color: var(--openmrs-background-grey);
top: var(--spacing-09);
display: flex;
}
.stickyResultsHeader {
padding: var(--spacing-03) 0;
z-index: 10;
background-color: var(--openmrs-background-grey);
top: var(--spacing-09);
display: flex;
position: sticky;
border-bottom: 1px solid #e1e1e1e1;
}