Skip to content

Loading State

LoadingState is the standard async placeholder. It uses role="status" and aria-live="polite" so assistive technology announces the loading state without interrupting the user. Every fetch in the UI should show LoadingState while pending — never leave a blank area or a raw spinner.

Live demo

Usage

import { LoadingState } from "@beacon/design-system";
// Default label
<LoadingState />
// Custom label
<LoadingState label="Loading invoices..." />

With TanStack Query

const { data, isLoading } = useQuery(invoiceListQuery);
if (isLoading) {
return <LoadingState label="Loading invoices..." />;
}

Full-page loader

<AppShell primaryNav={nav}>
{isLoading ? <LoadingState label="Loading..." /> : <PageContent data={data} />}
</AppShell>

Props

PropTypeDefaultDescription
labelstring"Loading"Text label rendered below the spinner and read by screen readers.

Design tokens used

TokenRole
--ds-color-accent-defaultSpinner color.
--ds-color-content-dimLabel text.
--ds-space-mdSpacing between spinner and label.

Accessibility

The root renders with role="status" and aria-live="polite". The spinner SVG carries aria-hidden="true" so screen readers read the text label only, not the animation. The label prop is the announced text — make it descriptive enough to identify what is loading (e.g. "Loading invoices..." rather than "Loading...").

When to use

Every isLoading branch of a TanStack Query result. The pattern is: isLoading shows LoadingState, isError shows ErrorState, success renders the content. Do not skip the loading state — it prevents layout flicker and gives users feedback that data is on its way.