#scroll event handler not working

1 messages · Page 1 of 1 (latest)

little goblet
#

the event handler that is supposed to trigger onScrollEnd() when it reaches the bottom of the scroll area is not working

type DataPopoverProps<T> = { data: T[] renderCardAction: (item: T, index: number) => React.ReactNode triggerLabel?: string, selected: number | undefined, onSelectAction: (index: number) => void onScrollEnd?: () => void loading?: boolean } export default function DataPopover<T>({data, renderCardAction, triggerLabel="Open", selected, onSelectAction, onScrollEnd, loading} : DataPopoverProps<T>) { const scrollReference = React.useRef<HTMLDivElement>(null); const [comboboxOpen, setComboboxOpen] = React.useState(false); const [triggerLabelState, setTriggerLabelState] = React.useState(triggerLabel); useEffect(() => { const reference = scrollReference.current if (onScrollEnd && reference) { const handleScroll = () => { const reachedBottom = reference.scrollTop + reference.clientHeight >= reference.scrollHeight - 5; if (reachedBottom) { onScrollEnd(); } } reference.addEventListener("scroll", handleScroll); return () => { reference.removeEventListener("scroll", handleScroll);} } }, [onScrollEnd]) return ( <div className={""}> <Popover open={comboboxOpen} onOpenChange={setComboboxOpen}> <PopoverTrigger asChild> <Button role={"combobox"} variant={"outline"}> {triggerLabel} <ChevronDown /> </Button> </PopoverTrigger> <PopoverContent className={"p-0"}> {/*TODO: make scrollbar look better with tailwind-scrollbar plguin after upgrading to tailwind 4.x*/} <div className={""} > <Command className={"p-1 max-h-60 overflow-y-auto"} ref={scrollReference}> { data.map((item,index) => ( <CommandItem key={index} onSelect={() => { setComboboxOpen(false) onSelectAction(index)}}> <div> {renderCardAction(item, index)} </div> </CommandItem> ))} { loading && <CommandItemclassName={"flex items-center justify-center [&_svg]:!size-auto p-4"}> <Spinner size={"medium"}className={"text-neutral-400"}/> </CommandItem> } </Command> </div> </PopoverContent> </Popover></div> )}
sudden harnessBOT
#

Hi @little goblet. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

Based on the knowledge sources provided, scroll event handlers in Next.js can sometimes fail to work as expected when the scrollable area is not the window but a nested element (such as a div with overflow-y-auto). This is a known issue, especially when you set a fixed height and overflow on a container: Next.js's default scroll restoration and event handling often target the window, not nested scroll containers. As a result, scroll events or scroll-to-top logic may not trigger as expected on these inner elements.

A relevant workaround, as described in the sources, is to ensure that your scroll event handler is attached directly to the scrollable element and that you are referencing the correct DOM node. In your code, you are using a ref and adding the event listener in a useEffect, which is correct. However, you should ensure:

  1. The ref is correctly attached to the scrollable element (the one with overflow-y-auto).
  2. The element is rendered and available when the effect runs.
  3. The event listener is not being removed or re-added unnecessarily.

From your code, it looks like you are attaching the ref to the <Command> component. If <Command> is not a native DOM element or does not forward refs to a DOM node, the ref will be null, and the event listener will not be attached. This is a common pitfall in React when using custom components.

Solution:

  • Make sure <Command> forwards its ref to a native DOM element (like a div).
  • Alternatively, attach the ref and event listener to a native div that wraps your scrollable content.

Here’s a simplified example based on a solution from the knowledge sources:

// Ensure the ref is attached to a native element with overflow-y-auto
<div
  id="myContainer"
  ref={scrollReference}
  className="p-1 max-h-60 overflow-y-auto"
>
  {/* ...your content... */}
</div>

And in your effect:

#
useEffect(() => {
  const reference = scrollReference.current;
  if (onScrollEnd && reference) {
    const handleScroll = () => {
      const reachedBottom =
        reference.scrollTop + reference.clientHeight >= reference.scrollHeight - 5;
      if (reachedBottom) {
        onScrollEnd();
      }
    };
    reference.addEventListener("scroll", handleScroll);
    return () => {
      reference.removeEventListener("scroll", handleScroll);
    };
  }
}, [onScrollEnd]);

This approach is confirmed to work in similar scenarios where scroll events on nested containers were not firing as expected, as long as the ref is attached to the correct DOM node and not a custom component that does not forward refs. If you are using a custom component, you must ensure it uses React.forwardRef to pass the ref down to the actual DOM element Limiting h-[100vh]/screen and overflow-y-scroll prevents scrollToTop on searchParams update.

If you are still experiencing issues, double-check the ref attachment and consider moving the scrollable class and the ref to a plain div.

Summary:
The most likely cause is that your ref is not attached to a native scrollable element. Attach the ref and event listener to a native div with overflow-y-auto, not a custom component, unless it forwards refs properly. This matches the solution found in the knowledge sources.

If you need more details or a specific example, let me know!

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: