Skip to content
Component installs need the registry setup
VegaStack Design

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
stable
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-more

The 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 onLoadMore again. Rows already loaded stay where they are.
  • Done — nothing, unless the host passes endLabel: a list that simply stops needs no caption.
End of list

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

PropTypeDefaultDescription
hasMore*boolean—More rows exist beyond the ones already loaded.
onLoadMore*() => void—Fetch the next batch. Also the retry after an error.
classNamestring—Classes merged onto the root.
endLabelReact.ReactNode—What to show once hasMore is false. Nothing renders when omitted.
errorReact.ReactNode—The last fetch failed. Shown as a message above a "Try again" button; rows already loaded stay.
labelstring"Load more"The button's label while more rows exist.
loadingbooleanfalseA fetch is in flight: the button shows a spinner, keeps its width and ignores further presses.
refReact.Ref<HTMLDivElement>—Ref to the root div.
retryLabelstring"Try again"The button's label after an error.

Data attributes and CSS variables on LoadMore

AttributeValues
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.
  • DataList and DataGrid set aria-rowcount="-1" on the table while hasMore is true, because the total is unknown.
KeyAction
TabMove to the button.
Enter / SpaceLoad the next batch, or retry after a failure.
ContractStates tested
Behaviouridle, loading, error, done, hidden
Accessibilitylabeled, busy, alert, focus-retained, browser-accessibility-test
Visualdefault, hover, focus-visible, loading, error

Do / Don't

Do
Keep the rows already loaded when a batch fails, and let Try again fetch the same batch.
Don't
Show a total or page numbers on a keyset list — use DataListPager when the total is known.

On this page