Load More
The shared Load more footer for keyset lists — load the next batch, retry a failed one, and optionally say the list has ended.
- Status
- Since
0.18.0- Accessibility pattern
- named button, busy state, alert on failure, focus kept
Last updated
- Task 1
- Task 2
- Task 3
Install
Add Load More from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.
pnpm dlx shadcn@latest add @vegastack/load-moreThe same command installs the registry items it composes: @vegastack/button.
Usage
import { LoadMore } from "@/components/ui/load-more";
<LoadMore
hasMore={nextCursor != null}
loading={isFetchingNextPage}
error={fetchError ? "Couldn't load more tasks." : undefined}
onLoadMore={fetchNextPage}
/>;LoadMore is the footer of a keyset list — one fetched by cursor, with no total and no page
numbers. It says only what the reader can do next: load the next batch, or retry the batch that
failed. It is controlled and owns no data: the host holds hasMore, loading and error, and
onLoadMore fetches the next batch (a retry is the same call).
DataList and DataGrid render it for you through their loadMore prop, and LoadMoreState — the
four paging fields on their own — is the shape those props, board lanes and useAsyncSearch pass
around. Reach for the component directly only for a list that is not a DataList or DataGrid.
- Task 1
- Task 2
- Task 3
Examples
States
- Idle — an outline button, Load more.
- Loading — the same button with a spinner. It keeps its width and its name, reports
aria-busy, and ignores further presses. - Error — the message above a Try again button, which calls
onLoadMoreagain. Rows already loaded stay where they are. - Done — nothing, unless the host passes
endLabel: a list that simply stops needs no caption.
Couldn't load more tasks.
Labels
label and retryLabel rename the two buttons, for a more specific verb or another language.
<LoadMore
hasMore={hasMore}
onLoadMore={fetchNextPage}
label="Show more meetings"
retryLabel="Retry"
endLabel="That's every meeting"
/>API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
hasMore* | boolean | — | More rows exist beyond the ones already loaded. |
onLoadMore* | () => void | — | Fetch the next batch. Also the retry after an error. |
className | string | — | Classes merged onto the root. |
endLabel | React.ReactNode | — | What to show once hasMore is false. Nothing renders when omitted. |
error | React.ReactNode | — | The last fetch failed. Shown as a message above a "Try again" button; rows already loaded stay. |
label | string | "Load more" | The button's label while more rows exist. |
loading | boolean | false | A fetch is in flight: the button shows a spinner, keeps its width and ignores further presses. |
ref | React.Ref<HTMLDivElement> | — | Ref to the root div. |
retryLabel | string | "Try again" | The button's label after an error. |
Data attributes and CSS variables on LoadMore
| Attribute | Values |
|---|---|
data-slot | "load-more" | "load-more-error" |
data-state | "done" | "error" | "idle" | "loading" |
LoadMoreState is exported too: hasMore, onLoadMore, loading and error, the props a list or
a data hook passes through as one value.
Accessibility
- The control is a real button named by its visible label. While loading it stays focusable and
reports
aria-busy="true"; the label keeps its box at opacity 0, so the name survives. - The button swaps its label and busy state in place rather than remounting, so keyboard focus stays on it while the new rows are appended above.
- A failed fetch renders its message as
role="alert": it appears because of something the reader just did. DataListandDataGridsetaria-rowcount="-1"on the table whilehasMoreis true, because the total is unknown.
| Key | Action |
|---|---|
| Tab | Move to the button. |
| Enter / Space | Load the next batch, or retry after a failure. |
| Contract | States tested |
|---|---|
| Behaviour | idle, loading, error, done, hidden |
| Accessibility | labeled, busy, alert, focus-retained, browser-accessibility-test |
| Visual | default, hover, focus-visible, loading, error |