#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
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>
);
}
#More examples
Record 1
Record 2
Record 3
Record 4
Record 5
Record 6
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>
);
}
#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.
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 |