react-scroll icon indicating copy to clipboard operation
react-scroll copied to clipboard

Not enough space at the bottom of the page to set Link as active

Open ShiiRochi opened this issue 6 years ago • 21 comments

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.

ShiiRochi avatar Jun 27 '18 09:06 ShiiRochi

I just added a span with 300px padding below the last element. Worked fine in my case.

thm-design avatar Jul 04 '18 20:07 thm-design

@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.

fisshy avatar Jul 04 '18 20:07 fisshy

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

ShiiRochi avatar Jul 15 '18 21:07 ShiiRochi

Not sure if its doable, but you could expand 2 and put 3 inside 2.

fisshy avatar Jul 16 '18 11:07 fisshy

Perhaps something like VisSense could be used to determine if one section is more visible than another?

AdamGerthel avatar Nov 06 '18 21:11 AdamGerthel

I have same isssue

ndinhphi avatar Nov 26 '18 11:11 ndinhphi

Any solution for this issue?

fmturati avatar Sep 13 '19 04:09 fmturati

@fmturati I usually put some margin at the bottom

fisshy avatar Sep 13 '19 05:09 fisshy

Yes, I added margin bottom for while... later on I will add more content to that section.... Thanks for answering me!

fmturati avatar Sep 13 '19 05:09 fmturati

still not fixed properly?

online0227 avatar Oct 09 '19 13:10 online0227

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;
  }

ckeeney avatar May 08 '20 23:05 ckeeney

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:

  1. Library could also accept some breakpoints, where to highlight each block by default, but it could result in a complex logic.

  2. Also...library can allow user to determine what item should be highlighted by passing info in a callbacks about block visibility.

ShiiRochi avatar May 11 '20 09:05 ShiiRochi

What about simply adding an option like "bottomElement" and make it active if scrolled to bottom?

nick4fake avatar Jul 19 '20 06:07 nick4fake

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>

marksy avatar Jul 29 '20 02:07 marksy

Please this is a really important fix!

LucianoTrujillo avatar Nov 21 '20 23:11 LucianoTrujillo

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.

FrancoMuniz avatar Nov 21 '20 23:11 FrancoMuniz

Having the same issue

iraqwarvet31 avatar May 15 '21 17:05 iraqwarvet31

If somebody is wondering, it is still haven't been fixed

ugnelis avatar Jan 31 '22 14:01 ugnelis

I'm not sure how this issue should be fixed, And I welcome any PR solving it.

fisshy avatar Jan 31 '22 20:01 fisshy

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

plffy avatar Dec 10 '22 18:12 plffy

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 ::)

darioackermann avatar Nov 11 '23 21:11 darioackermann