react-scroll
react-scroll copied to clipboard
Not enough space at the bottom of the page to set Link as active
I have components SideMenu and BlocksRenderer. In SideMenu, Links are rendered and by clicking on them we're scrolling to the relative Element in BlocksRenderer. I'm using 'spy' mode to automatically highlight Links while mouse scrolling. However, I haven't enough space after last two blocks, i.e. page's height is not enough and their links are never highlighted as active. What can or should I do to overcome this issue and set them active after clicking on them and at the same time using spy mode on all Links? Maybe there is a way to pass Link instance through the event and set it active after the scroll to the Link's relative Element is completed? P.S. Blocks can have different height. P.P.S. There could be an unlimited amount of blocks.
I just added a span with 300px padding below the last element. Worked fine in my case.
@thm-design thats usually what I do as well, if the scroll can't scroll down to the element, then it's impossible to determine the active link, unless it's forced by the clicked link, but then it would be interrupted once the scrollbar was moved.
Is there a way to set link's active state in case the user's scroll position is exactly between two elements? For example, I have a sidebar with 3 Links, in the body of the page I have 5 elements: 1 - not scroll target 2 - scroll target 3 - not scroll target 4 - scroll target 5 - scroll target And if the user's scroll is between (2) and (4) I need to set (2) as active
Not sure if its doable, but you could expand 2 and put 3 inside 2.
Perhaps something like VisSense could be used to determine if one section is more visible than another?
I have same isssue
Any solution for this issue?
@fmturati I usually put some margin at the bottom
Yes, I added margin bottom for while... later on I will add more content to that section.... Thanks for answering me!
still not fixed properly?
A slightly cleaner solution is to ensure the last section is tall enough. I gave all my sections a .section
class and then added to the container:
.section:last-child {
min-height: 100vh;
}
I’am not working close with a project that faced that issue anymore, but this issue is still opened.
I have the following thoughts on the matter.
So...to determine what item X from N visible items should be highlighted there should be some criteria.
For example, when 3 items are visible at the same time and all are equally dividing currently visible viewport between each other...there is only one question from the point of view of the package: “which one should I highlight?”
Also, there could be one more question: “may I highlight all visible?”, but this is another story...
Currently, I think, package has a solid logic about it.
We, as users, who see application could say: “If user viewport has reached the bottom of a page, then I want to highlight the most bottom link”. However, how the package could determine when to highlight block above the most bottom one.
If being at the bottom of the page last item should be highlighted, then it can result in a case, where pixels region, where block above should be highlighted, would be very wise for us, so it will be a pixel contest to catch a right position when block is highlighted (even some .000000003px may be important).
Thus...simple solution is to keep enough distance between blocks, between blocks section start and first block, and between blocks section end and last block.
Other possible solutions:
-
Library could also accept some breakpoints, where to highlight each block by default, but it could result in a complex logic.
-
Also...library can allow user to determine what item should be highlighted by passing info in a callbacks about block visibility.
What about simply adding an option like "bottomElement" and make it active if scrolled to bottom?
yeah i made a dummy component <LastPage />
with height:54vh
to fill the bottom void, which looks like overscrolling but fixes the last link active issue:
<Pages>
{data.map((page: PageDataProps, index: number) => (
<PageItem key={`page-${page.id}`}>
{page.isLoading ? (
<Page id={page.id}>
<StyledLoadingSpinner color={'black'} justify={'space-between'} />
</Page>
) : (
<Page id={page.id} />
)}
</PageItem>
))}
<LastPage />
</Pages>
Please this is a really important fix!
Has anyone found any nice fix for this? Same thing as everyone, I'm adding extra margin at the bottom to toggle last section's Link.
Having the same issue
If somebody is wondering, it is still haven't been fixed
I'm not sure how this issue should be fixed, And I welcome any PR solving it.
One solution can be, we set a negative offset value that will make the last element active even it is not at the top. And, disable the navigation on click rather use onClick props and manually navigate to the selected element. I had also asked a sage question on this - https://stackoverflow.com/questions/74753194/react-customise-react-scroll-behaviour
Hi all
In case this is still relevant for anyone, create a hook, I called it useOnScreen
import {useEffect, useMemo, useState} from "react";
export default function useOnScreen(name: string) {
const [isIntersecting, setIntersecting] = useState(false)
const observer = useMemo(() => new IntersectionObserver(
([entry]) => setIntersecting(entry.isIntersecting)
), [])
useEffect(() => {
const mutOb = new MutationObserver(() => {
const el = document.getElementsByName(name)[0];
if(el)
observer.observe(el)
})
mutOb.observe(document, {
attributes: true,
subtree: true
})
}, [])
return isIntersecting
}
Then, at the place where you use your Link
const SidebarScrollItem = ({ title, icon, to }: SidebarScrollLinkItemProps) => {
// ....
const isVisible = useOnScreen(to);
return (
<Link
className={`nav-link ${isVisible ? 'active' : ''}`}
role="button"
to={to}
containerId="main"
smooth={true}
>
// ...
</Link>
);
Hope it helps ::)