# ErrorBoundary

**When to use:** Wrap any subtree whose render errors shouldn't take down the rest of the app — a widget, a route, a third-party embed, a list row. It catches JavaScript errors thrown while rendering descendants (via React's `getDerivedStateFromError` / `componentDidCatch`) and swaps in a fallback UI instead of unmounting the whole tree. Only errors thrown during rendering, in lifecycle methods, or in constructors of the tree below it are caught — event handlers, async code, and errors in the boundary itself are not, same as any React error boundary.

**Keywords:** crash handler, error catching

**Import:** `import { ErrorBoundary } from '@ahrowe/ui'`

```tsx
import { ErrorBoundary } from '@ahrowe/ui';

// Basic — default fallback with a "Try again" button
<ErrorBoundary>
  <Widget />
</ErrorBoundary>

// Report to your error tracker, and re-arm whatever caused the crash on reset
<ErrorBoundary
  onError={(error, errorInfo) => reportToSentry(error, errorInfo)}
  onReset={() => setWidgetKey((k) => k + 1)}
>
  <Widget />
</ErrorBoundary>

// Custom copy, no stack-trace section (e.g. for a small inline widget)
<ErrorBoundary
  title="Widget crashed"
  description="This panel failed to load. The rest of the page is unaffected."
  hideStack
>
  <Widget />
</ErrorBoundary>

// Fully custom fallback UI — render function receives the error and a reset callback
<ErrorBoundary
  fallback={({ error, resetErrorBoundary }) => (
    <div>
      Something broke: {error.message}
      <button onClick={resetErrorBoundary}>Retry</button>
    </div>
  )}
>
  <Widget />
</ErrorBoundary>

// Auto-reset when inputs the crash depends on change (e.g. a route or record id)
<ErrorBoundary resetKeys={[recordId]}>
  <RecordDetail id={recordId} />
</ErrorBoundary>

// Translated strings for a non-English app — title/description are their own
// props (see above); labels covers everything else the built-in fallback renders
<ErrorBoundary
  title="Etwas ist schiefgelaufen"
  labels={{
    stackTrace: 'Stapelverfolgung',
    copy: 'Kopieren',
    copied: 'Kopiert',
    reset: 'Erneut versuchen',
    copySuccessToast: 'Stapelverfolgung kopiert',
    copyErrorToast: 'Kopieren fehlgeschlagen',
  }}
>
  <Widget />
</ErrorBoundary>
```

The default fallback is a centered card with a tinted icon badge, an `Accordion` for the collapsible stack trace (with a `CopyButton` that also fires a `Toast` confirmation when the boundary is inside `AhroweProvider`), and a `Button` for "Try again".

Put an app-wide boundary inside `AhroweProvider`, not around it. Around it, the error has unmounted the provider by the time the fallback shows, so the fallback renders unthemed and its copy confirmation never appears.

**Key props:**

| Prop | Type | Description |
|------|------|-------------|
| `children` | `ReactNode` | The subtree to protect |
| `title` | `ReactNode` | Heading in the default fallback (default `"Something went wrong"`) |
| `description` | `ReactNode` | Overrides the message shown under the title. Defaults to `error.message` |
| `labels` | `ErrorBoundaryLabels` | Overrides for every other built-in string (stack trace label, copy button tooltip, reset button text, copy toasts) — pass a translated set for non-English apps. See below |
| `fallback` | `ReactNode \| (props: ErrorBoundaryFallbackProps) => ReactNode` | Replaces the built-in fallback entirely. The render-function form receives `{ error, errorInfo, resetErrorBoundary }` |
| `onError` | `(error: Error, errorInfo: ErrorInfo) => void` | Called once per catch — the place to report to Sentry/Datadog/etc. |
| `onReset` | `() => void` | Called after the boundary is reset, whether via the built-in "Try again" button, a custom fallback calling `resetErrorBoundary`, or a `resetKeys` change. Use it to re-arm whatever state caused the crash |
| `resetKeys` | `unknown[]` | When any value in this array changes while the boundary is showing an error, it resets automatically — mirrors the common `react-error-boundary` pattern |
| `hideStack` | `boolean` | Hide the collapsible stack-trace section. Default `false` |

**`ErrorBoundaryLabels`:**

| Field | Default | Description |
|-------|---------|--------------|
| `stackTrace` | `"Stack trace"` | Accordion header for the stack trace section |
| `copy` | `"Copy"` | Copy button tooltip and accessible name before copying |
| `copied` | `"Copied"` | Copy button tooltip and accessible name right after a successful copy |
| `reset` | `"Try again"` | Reset button label |
| `copySuccessToast` | `"Stack trace copied to clipboard"` | Toast shown after a successful copy, inside `AhroweProvider` only |
| `copyErrorToast` | `"Could not copy stack trace"` | Toast shown if the copy fails, inside `AhroweProvider` only |

**Slots:** `root` `header` `badge` `icon` `title` `description` `stack` `stackHeader` `stackLabel` `stackTrace` `copyButton` `actions` `resetButton`
