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

onLoadMore prop for react-aria-components ListBox

Open Talor-A opened this issue 2 years ago โ€ข 7 comments

Provide a general summary of the feature here

it appears that useListBox and react-spectrum/ListBox both support an onLoadMore prop, but react-aria-components/ListBox doesn't expose one. it would be great to have this feature.

๐Ÿค” Expected Behavior?

    <ListBox
      items={list.items}
      isLoading={list.isLoading}
      onLoadMore={list.loadMore}
    >
      {(item) => <Item key={item.name}>{item.name}</Item>}
    </ListBox>

๐Ÿ˜ฏ Current Behavior

no onLoadMore prop exists

๐Ÿ’ Possible Solution

No response

๐Ÿ”ฆ Context

trying to replace our reliance on downshift with just one library with react-aria. if there's a workaround I can use by creating a custom <ListBox/> component using useListBox and ListBoxContext, that would work here too.

๐Ÿ’ป Examples

No response

๐Ÿงข Your Company/Team

replit.com

๐Ÿ•ท Tracking Issue

No response

Talor-A avatar Nov 29 '23 02:11 Talor-A

This is something we definitely want to support at some point soon. We will also want consider eventually supporting virtualization which is related, but that could be added added later (and would be non-breaking). We might also consider adding an onScroll event, which would work for this.

reidbarber avatar Nov 30 '23 23:11 reidbarber

nice, thanks! do you know if there's any way to work around the issue in the meantime?

Talor-A avatar Nov 30 '23 23:11 Talor-A

I think you can probably pass in a ref, then inside a useEffect, add a scroll event listener to the element directly via the ref. You would want to keep track of the max e.target.scrollTop value reached, then load more data every time max % threshold === 0, where threshold is how many px you want to scroll before loading more data.

reidbarber avatar Nov 30 '23 23:11 reidbarber

I think you can probably pass in a ref, then inside a useEffect, add a scroll event listener to the element directly via the ref. You would want to keep track of the max e.target.scrollTop value reached, then load more data every time max % threshold === 0, where threshold is how many px you want to scroll before loading more data.

makes sense, I'll give it a shot โ€“ thanks for your help!

Talor-A avatar Dec 01 '23 02:12 Talor-A

here's my completed workaround. seems to work great, thanks @reidbarber !


function ListBoxInner<T extends object>(
  { dataCy, onLoadMore, ...props }: ListBoxProps<T>,
  ref: React.Ref<HTMLDivElement>,
) {
  const scrollRef = React.useRef<HTMLDivElement>(null);

  useIsomorphicLayoutEffect(() => {
    const el = scrollRef.current;
    if (!el) {
      return;
    }

    const onScroll = () => {
      if (
        el.scrollTop + el.clientHeight >=
        el.scrollHeight - LOAD_MORE_THRESHOLD
      ) {
        onLoadMoreRef?.();
      }
    };

    el.addEventListener('scroll', onScroll);

    return () => el.removeEventListener('scroll', onScroll);
  }, [onLoadMore]);

  return (
    <AriaListBox<T>
      css={style.listbox}
      data-cy={dataCy}
      {...props}
      ref={mergeRefs(ref, scrollRef)}
    />
  );
}

export const ListBox = React.forwardRef(ListBoxInner);

Talor-A avatar Dec 01 '23 19:12 Talor-A

onScroll is being added in https://github.com/adobe/react-spectrum/pull/5534, so that may help people in the meantime.

reidbarber avatar Dec 06 '23 16:12 reidbarber

Hello! Are there any updates on this?

junlarsen avatar May 30 '25 14:05 junlarsen

Support for infinite scrolling was added across all collection components including ListBox in our latest release. See the release notes and docs.

devongovett avatar Jul 23 '25 20:07 devongovett