> Leaf UI 0.8.1 · Package: @ifhover/leaf-ui · Source: 435bab23cad7d343653d9b63b049c0b0601eeefb
> Browser documentation: https://ifhover.github.io/leaf-ui/en/components/infinite-scroll.html

> For AI agents: the complete documentation index is available at https://ifhover.github.io/leaf-ui/en/llms.txt, the full documentation bundle is available at https://ifhover.github.io/leaf-ui/en/llms-full.txt.

# InfiniteScroll

Load more content when reaching the end of a list.

## Basic usage


Item 1

Item 2

Item 3

Item 4

Item 5

Item 6

Item 7

Item 8

Item 9

Item 10

basic.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/infinite-scroll/basic.tsx"
import { InfiniteScroll, ScrollArea } from '@ifhover/leaf-ui';

import { useRef, useState } from 'react';

export function InfiniteScrollBasic() {
  const root = useRef<HTMLDivElement>(null);
  const [items, setItems] = useState(() => Array.from({ length: 10 }, (_, i) => i));
  return (
    <ScrollArea ref={root} height={240} aria-label="Growing list">
      <InfiniteScroll
        dataLength={items.length}
        hasMore={items.length < 40}
        target={() => root.current}
        onLoadMore={async (signal) => {
          await new Promise((resolve) => setTimeout(resolve, 500));
          if (!signal.aborted)
            setItems((previous) => [
              ...previous,
              ...Array.from({ length: 10 }, (_, index) => previous.length + index),
            ]);
        }}
      >
        {items.map((item) => (
          <div key={item} style={{ padding: '12px 16px' }}>
            Item {item + 1}
          </div>
        ))}
      </InfiniteScroll>
    </ScrollArea>
  );
}
```

Expand code

## More examples


Record 1

Record 2

Record 3

Record 4

Record 5

Record 6

advanced.tsx

Copy code

```tsx lineNumbers file="../../../src/examples/en/infinite-scroll/advanced.tsx"
import { InfiniteScroll, ScrollArea } from '@ifhover/leaf-ui';

import { useRef, useState } from 'react';

export function InfiniteScrollRetry() {
  const root = useRef<HTMLDivElement>(null);
  const attempt = useRef(0);
  const [items, setItems] = useState([0, 1, 2, 3, 4, 5]);
  return (
    <ScrollArea ref={root} height={180} aria-label="Retry example">
      <InfiniteScroll
        dataLength={items.length}
        hasMore={items.length < 12}
        target={() => root.current}
        onLoadMore={async (signal) => {
          await new Promise((resolve) => setTimeout(resolve, 300));
          if (signal.aborted) return;
          if (attempt.current++ === 0) throw new Error('Retry demo');
          setItems((previous) => [...previous, ...[6, 7, 8, 9, 10, 11]]);
        }}
      >
        {items.map((item) => (
          <p key={item}>Record {item + 1}</p>
        ))}
      </InfiniteScroll>
    </ScrollArea>
  );
}
```

Expand code

## Usage

Return a Promise from onLoadMore; requests do not overlap. Update dataLength after appending. The signal aborts on unmount and failures can be retried.

## Types

Import these types for data, callbacks and refs.

```ts
import type { InfiniteScrollProps } from '@ifhover/leaf-ui';
```

## InfiniteScrollProps API

| Property     | Type                                     | Default  | Description                                  |
| ------------ | ---------------------------------------- | -------- | -------------------------------------------- |
| `dataLength` | `number`                                 | Required | Loaded count; changes allow the next request |
| `hasMore`    | `boolean`                                | Required | More data remains                            |
| `onLoadMore` | `(signal: AbortSignal) => Promise<void>` | Required | Load more; signal aborts the request         |
| `target`     | `() => HTMLElement \| null`              | —        | Scroll target or link target                 |
| `threshold`  | `number`                                 | `200`    | Pixels from the end that trigger loading     |
| `loader`     | `ReactNode`                              | —        | Loading placeholder                          |
| `endMessage` | `ReactNode`                              | —        | Content after all items are loaded           |
| `onError`    | `(error: unknown) => void`               | —        | Error callback                               |
