A failure in a region is two things at once: something the reader has to understand, and
something they have to do about it. `ErrorState` is the one surface in the library whose whole
purpose is to say both, what failed, what it cost them, and, when there is anything left to try,
the retry sitting beside the explanation rather than three screens away.

It is `EmptyState` with the error tone: the same centred block and the same action group, plus a
retry and a disclosure for the message the request returned. It is drawn as a panel and announced
as an `alert` by default, because it usually replaces content a moment after a request failed.

```tsx demo="feedback/error-state-preview"
```

## Usage

```tsx
import { ErrorState } from "@asheeui/web";

<ErrorState
  title="Invoices could not be loaded"
  description="The request timed out. Trying again usually works."
  onRetry={refetch}
/>
```

`onRetry` is a React handler rather than a configured action, because a configured action describes
a destination and "run that request again" is not one. Its presence is what draws the control:
without `onRetry` the state offers no retry at all, which is the honest arrangement when nothing
can be retried. The control it draws is a solid, danger-coloured button, which is what makes the
retry the primary action of a failed region rather than one option among several.

`description` is where the reassurance goes, *nothing has been charged*, *the draft is saved*,
because a reader who has just lost sight of their data is asking what it cost them before they ask
how to get it back. `retryLabel` renames the control for the cases where "Try again" is too vague
about what is being tried again, and both that label and `detailLabel` take a node rather than a
string, so either control can carry an icon; what a reader hears is the text the node renders.

## The technical detail

`detail` is the message a request returned, and it is written for a developer. It renders folded
into a disclosure labelled by `detailLabel` and opened only when someone asks, so the reader who
needs it can paste it into a support ticket and the reader who does not is never shown a stack
trace. The disclosure is the platform's own `<details>`, so it opens without scripting and is
announced with its open state.

```tsx demo="feedback/error-state-detail"
```

## When trying again is not the answer

`primaryAction` and `secondaryAction` are the same configurations `EmptyState` takes, and they share
one group with the retry: the configured actions first, the retry after them. That order is
deliberate, the configured pair is the consumer's own statement of where the reader can go and
leads the row, while the retry is the framework's recovery path for the request that failed. When
no configured action is given the retry is the only control, and therefore first. A permission
failure is the case worth designing for, there is no request worth running again, so the state
explains, and offers the two destinations that can actually help.

```tsx demo="feedback/error-state-actions"
```

## Props

```props ErrorState
```

`size`, `panel`, `role`, `retryLabel` and `detailLabel` resolve instance → `components.errorstate` →
the framework's fallback, registered as `md`, `true`, `alert`, `Try again` and `Technical details`.
The default panel and the default alert are one decision seen twice: this state usually replaces a
region that was there a moment ago, so it draws the surface it replaced and says what happened.
An `ErrorState` is dressed by `components.errorstate` alone, it composes the empty presentation
but states its own density and its own surface, so restyling the one does not restyle the other.

`title`, `titleAs`, `description`, `detail`, `onRetry`, `primaryAction`, `secondaryAction`, `icon`,
`as` and `children` are instance-only. There is no `type`: a failure is the error tone, and a
component that could be told to look like a success is a component that would lie about the data.

## Accessibility

- The state is an `alert` by default, and that is a statement about timing. A reader mid-task is
  interrupted because a request they started has just failed: silence would leave them waiting for
  content that is not coming.
- `role="status"` is the polite version, for a failure that is not the result of what the reader
  just did, a background refresh, a second region that failed while they were reading the first.
  It waits for a pause instead of cutting in.
- `role="none"` renders no live region at all, for a failure that was part of the page from the
  start, such as a not-found page: there was no change, so there is nothing to announce.
- The retry is a real `<button type="button">` and the disclosure is a `<summary>` inside
  `<details>`, so both are keyboard-operable and both are reached by tabbing. Focus is never moved
  to either: the failure reports, and the reader decides when to act on it.
- The title renders as a heading, an `<h2>` unless `titleAs` states another level, so a reader can
  reach the failure by heading navigation, the same way they reach a section. `titleAs` is how a
  failure that *is* the page renders an `h1`, and how one inside a card's `h3` renders an `h4`.

The two channels, and why a retry never moves focus, are
[Announcements](/concepts/announcements).

## Related

```related empty-state, loading-state, button
```
