Source: https://monarchui.dev/components/inline-error-retry/

Components · Status and feedback

# InlineErrorRetry

A compact "this part didn’t load" row with Try again.

@rookcom/monarch-react

Component

## Inline, with a pending retry

## Usage examples

### Banner above stale data

## Purpose

Reports that one section of a working page failed to load and lets the person retry it in place, without replacing the whole region.

### Use when

- A card, widget or list section failed while the rest of the page loaded.
- A refresh failed but older data is still shown (`variant="banner"`, `tone="warning"`).
- A form field’s options failed to load (a country list, say).

### Avoid when

- The whole region failed and has nothing else to show: use ErrorState.
- The whole route failed: use ErrorPage.
- The message is not an error: use Alert.

## Design principles

- One sentence from the product saying what did not load, then Try again. No raw error text.
- Reassure when you can ("The rest of the dashboard is up to date").
- Quiet by default: `inline` is a plain row; `banner` adds a tint only when it must stand above stale data.

## API reference

```tsx
import { InlineErrorRetry } from '@rookcom/monarch-react';
```

| Export | Kind | Rendering | Root class |
| --- | --- | --- | --- |
| `InlineErrorRetry` | component | client | `.mn-inline-error-retry` |

Native `<div>` attributes pass through and the ref is forwarded to the root.

If `onRetry` returns a promise (a refetch), the button stays busy until it settles. Pass `retrying` to control the busy state yourself; the returned value is then ignored.

Extra actions go in `actions`, after Try again.

Generated from the TypeScript declarations of `packages/react/src/components/feedback/inline-error-retry`.

## Properties

### `InlineErrorRetry`

A compact "this part didn't load" row with Try again. It is announced when it appears and again when a retry fails; focus stays on Try again while the retry runs and moves to `returnFocusTo` if the row goes away.

| Prop | Type | Description |
| --- | --- | --- |
| `children` required | `ReactNode` | The failure in plain words, e.g. "Your earnings didn't load." Supplied by the product. |
| `onRetry` required | `() => unknown` | Called by Try again. Return a promise (a refetch) and the button stays busy until it settles; or control the busy state with `retrying`. |
| `actions` | `ReactNode` | Extra actions after Try again, such as a link to a status page. |
| `className` | `string` |  |
| `icon` | `ReactNode` | Replaces the warning icon. Pass `null` for none. Decorative. |
| `id` | `string` |  |
| `retrying` | `boolean` | Controlled busy state. When set, the returned promise is not tracked. |
| `retryingMessage` | `string` | Announced politely when a retry starts. Default "Retrying". |
| `retryLabel` | `string` | Retry button text. Default "Try again". |
| `returnFocusTo` | `InlineErrorRetryFocusTarget` | Where focus goes if this row unmounts while it holds focus, which usually means the retry worked and the content replaced it. Pass a ref or a function returning the element (the loaded region's heading, say). |
| `tone` | `"danger" \| "warning"` | `danger` (default) when nothing could load; `warning` when stale data is still shown. |
| `variant` | `"banner" \| "inline"` | `inline` (default) is a compact row inside a card or section; `banner` is a tinted, bordered strip, for example above stale data that is still shown. |

## Variants

| Prop | Values | Description |
| --- | --- | --- |
| `variant` | `'inline'``'banner'` | `inline` (default) is an unboxed row; `banner` adds a border, radius and tinted background. Exposed as `data-variant`. |
| `tone` | `'danger'``'warning'` | `danger` (default) when nothing could load; `warning` when stale data is still on screen. Exposed as `data-tone`. |

## States

| State | Exposed as | Behaviour |
| --- | --- | --- |
| Failed | – | The message and Try again. |
| Retrying | `data-retrying; aria-busy="true" on the button` | The button shows a spinner and ignores clicks but keeps focus; "Retrying" is announced politely. |
| Failed again | – | When a retry settles and the row is still shown, the message is re-inserted into the alert so it is announced again. |

## Interaction behaviour

- Try again calls `onRetry` once per attempt; repeat clicks while busy are ignored.
- Focus stays on Try again during and after a failed retry.
- When a successful retry removes the row while it holds focus, focus moves to `returnFocusTo` (a ref or a function), usually the loaded section’s heading.

## Keyboard support

| Keys | Action |
| --- | --- |
| Tab / Shift+Tab | Moves to Try again, then any extra actions. |
| Enter / Space | Retries. |

## Accessibility

Role

alert (the message) and status (the retrying announcement)

Accessible name

–

- The message sits in role="alert", so it is announced when the row appears and again after each failed retry.
- The "Retrying" announcement is a separate polite role="status", outside the alert, so it never interrupts.
- The busy button stays focusable (aria-disabled + aria-busy) so keyboard users do not lose their place.
- Without `returnFocusTo`, focus falls back to the document when the row disappears; give the loaded content a focusable heading (`tabIndex={-1}`) and pass it.
- The icon is `aria-hidden`; the spinner slows under `prefers-reduced-motion: reduce`.
- Verified with axe in jsdom and in Chromium, Firefox and WebKit on /components/inline-error-retry.

## Responsive behaviour

- A wrapping flex row: the message takes the remaining width (12rem minimum) and the actions drop below it on narrow screens, down to 320px.

## Theme support

- The icon uses `--mn-color-danger-strong` (or warning); `banner` uses the matching subtle background and border tokens.
- Colours are Monarch semantic tokens only, so light, dark and more-contrast themes apply automatically.

## Do and don't

### Do

- Name what did not load ("Your earnings didn’t load"), not that an error happened.
- Return the refetch promise from `onRetry`, or pass `retrying`.
- Pass `returnFocusTo` so keyboard users land on the loaded content.

### Don't

- Do not show the error message from the server.
- Do not stack several InlineErrorRetry rows for one failure; one per independent section.

## Related components

- [ErrorState](https://monarchui.dev/components/error-state/): The whole region failed and has nothing else to show.
- [Alert](https://monarchui.dev/components/alert/): A message that is not a load failure.
- [ErrorPage](https://monarchui.dev/components/error-page/): The whole route failed.

## Dependencies

| Kind | Depends on |
| --- | --- |
| npm packages | `react` |
| Monarch components | [Button](https://monarchui.dev/components/button/) |

## Testing coverage

- Announces the failure as an alert and retries from the keyboard.
- Uncontrolled: stays busy until the returned promise settles, keeps focus, ignores repeat clicks and announces "Retrying".
- Re-inserts the message after a failed retry so it is announced again.
- Controlled: follows `retrying` and re-announces on busy → idle.
- Moves focus to `returnFocusTo` when a successful retry removes it, and never steals focus it did not hold.
- Banner variant, warning tone, extra actions, custom labels and ref.

| Check | Covered |
| --- | --- |
| Axe in jsdom | Yes |
| Server rendering | Yes |
| Browser suites | Visual baselines: /__gallery; Cross-browser axe: /components/inline-error-retry |

Tests: `packages/react/src/components/feedback/inline-error-retry`

## All example code

### Inline, with a pending retry

```tsx
import { InlineErrorRetry } from '@rookcom/monarch-react';

const wait = () => new Promise<void>((resolve) => setTimeout(resolve, 1200));

<InlineErrorRetry onRetry={wait}>Your recent payouts didn’t load.</InlineErrorRetry>
```

### Banner above stale data

```tsx
import { InlineErrorRetry, Link } from '@rookcom/monarch-react';

const wait = () => new Promise<void>((resolve) => setTimeout(resolve, 1200));

<InlineErrorRetry variant="banner" onRetry={wait}>
  We couldn’t load this chart. The rest of the dashboard is up to date.
</InlineErrorRetry>
<InlineErrorRetry
  variant="banner"
  tone="warning"
  onRetry={wait}
  actions={<Link href="#status">View status</Link>}
>
  Showing data from 10 minutes ago.
</InlineErrorRetry>
```
