Components · Status and feedback
LoadingState
A region is loading: a layout-shaped skeleton or a labelled spinner, announced once.
List and rows
import { LoadingState } from '@rookcom/monarch-react';
<LoadingState label="Loading contacts" rows={3} />
<LoadingState label="Loading invoices" variant="rows" rows={3} />Usage examples
Cards and detail
import { LoadingState } from '@rookcom/monarch-react';
<LoadingState label="Loading projects" variant="cards" rows={3} />
<LoadingState label="Loading project" variant="detail" />Spinner
import { LoadingState } from '@rookcom/monarch-react';
<LoadingState label="Loading report…" variant="spinner" />Purpose
The placeholder shown while a list, table, card grid or detail view loads. It marks the region busy and announces what is loading once.
Use when
- A list with avatars is loading (
list, the default). - A table or plain list is loading (
rows). - A card grid is loading (
cards). - A detail view is loading (
detail). - The shape of the result is unknown, or a whole card or page is loading (
spinner).
Avoid when
- A single control is busy: use Button
loadingor Spinner. - Loading failed: use ErrorState or InlineErrorRetry.
- There is no data: use EmptyState.
Design principles
- Match the shape of what is coming, so the page does not jump when it arrives.
- Announce the label once and hide the skeleton shapes from assistive technology.
- A spinner always comes with visible text naming what is loading; never a bare spinner on a page.
API reference
import { LoadingState } from '@rookcom/monarch-react';| Export | Kind | Rendering | Root class |
|---|---|---|---|
LoadingState | component | server-safe | .mn-loading-state |
All native <div> attributes pass through, and the ref is forwarded to the root <div>.
Before 0.4 LoadingState lived in the error-state folder; the export, props and class names (mn-loading-state, __row, __lines) are unchanged.
Generated from the TypeScript declarations of packages/react/src/components/feedback/loading-state.
Properties
LoadingState
Skeleton placeholder with an aria-busy region and a live announcement.
| Prop | Type | Description |
|---|---|---|
label required | string | Announced to screen readers, e.g. "Loading tickets". |
children | ReactNode | |
className | string | |
id | string | |
rows | number | Skeleton rows to render (`list`, `rows` and `cards`). Default 4. |
variant | LoadingStateVariant | `list` (default) stacks avatar + text rows; `rows` stacks plain text rows (table and list-row preset); `cards` renders a grid; `detail` a title + paragraphs; `spinner` a centred spinner with the label shown. |
Variants
| Prop | Values | Description |
|---|---|---|
variant | 'list''rows''cards''detail''spinner' | list (default) stacks avatar + two text lines; rows stacks bordered text rows (table and list-row preset); cards a grid of blocks; detail a title and paragraphs; spinner a centred spinner with the label shown. Exposed as data-variant. |
rows | 'number' | Rows for list, rows and cards. Default 4; negative values render none. |
States
| State | Exposed as | Behaviour |
|---|---|---|
| Loading | aria-busy="true" | The root is always marked busy; unmount it when the content arrives. |
Interaction behaviour
Not interactive.
Keyboard support
Not interactive and not focusable.
Accessibility
- Role
- status inside an aria-busy region
- Accessible name
- The
labelprop, e.g. "Loading invoices".
- The label renders in a role="status" element: visually hidden for skeleton variants, visible next to the spinner for
spinner. - Skeleton shapes and the spinner are
aria-hidden. - Do not nest LoadingState inside another aria-busy region; announce completion from the loaded content if it matters.
- Verified with axe in jsdom and in Chromium, Firefox and WebKit on /components/loading-state.
Responsive behaviour
cardsuses an auto-fill grid with a 14rem minimum column that shrinks to one full-width column below 14rem.- Skeleton widths are percentages, so rows fit any container down to 320px.
Theme support
- Skeleton shapes use the Skeleton component (muted surface tokens);
rowsdividers use--mn-color-border-subtle. - The spinner label uses
--mn-color-text-muted. - Under
prefers-reduced-motion: reducethe skeleton shimmer stops and the spinner slows (from Skeleton and Spinner).
Do and don't
Do
- Give it a label naming what is loading.
- Pick the variant that matches the content that will replace it.
Don't
- Do not nest LoadingState inside another aria-busy region.
- Do not leave it mounted after the content arrives.
Related components
- Skeleton: The placeholder shapes LoadingState is built from.
- Spinner: A single busy control.
- ErrorState: Loading failed.
- EmptyState: Loaded, but nothing to show.
Dependencies
Testing coverage
- Announces its label as a status inside an aria-busy root.
- Default props keep the 0.3 markup and class names; the ref is forwarded.
rowsrenders plain text rows without avatars;cardsanddetailrender their shapes.spinnershows the label as visible status text and hides the spinner from assistive technology.- Negative
rowsrender no rows.
| Check | Covered |
|---|---|
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual baselines: /__gallery; Cross-browser axe: /components/loading-state |
Tests: packages/react/src/components/feedback/loading-state