Skip to content

ErrorBoundary

A failed panel should not expose diagnostic details or take down the rest of your page. ErrorBoundary replaces its failed subtree with a neutral message and a Try again button. Error messages and stack traces never appear in the default fallback.

import type { ReactNode } from 'react';
import { ErrorBoundary } from '@cratis/components/Common';
export function ProtectedSection({ children }: { children: ReactNode }) {
return <ErrorBoundary>{children}</ErrorBoundary>;
}

Healthy children render unchanged, without an extra wrapper. When a descendant fails, the default role="alert" fallback announces “Something went wrong. Please try again.” Its native button works without a Components provider or an adapter, including when renderer configuration caused the original error.

Retry remounts only the protected children. Their local state is lost, but state outside the boundary is preserved. Retry does not reload the page, retry a network request by itself, or guarantee that the cause is fixed. A persistent failure returns to the fallback; the boundary never retries automatically.

PropTypeDefaultPurpose
childrenReactNodeRequiredSubtree to protect.
fallbackReactNode | ((reset: () => void) => ReactNode)Neutral message and retry buttonCustom recovery UI. A callback receives only the reset action, not diagnostic data. An explicit null renders nothing.
onError(error: unknown, errorInfo: ErrorInfo) => voidConsole reporterApplication-controlled reporting of the thrown value and React component stack.
onReset() => voidNoneSynchronous callback before retry, for resetting host-owned failure state.

ErrorBoundaryProps is exported from @cratis/components/Common. ErrorInfo is React’s type. A child can throw a value other than an Error, so narrow error before reading its properties.

Use a fallback callback for translated text, application-specific navigation, or a different recovery action:

import type { ReactNode } from 'react';
import { ErrorBoundary } from '@cratis/components/Common';
export function RecoverableSection({
children,
clearFailedState,
}: {
children: ReactNode;
clearFailedState: () => void;
}) {
return (
<ErrorBoundary
onReset={clearFailedState}
fallback={(reset) => (
<div role='alert'>
<p>This section is temporarily unavailable.</p>
<button type='button' onClick={reset}>Retry section</button>
</div>
)}
>
{children}
</ErrorBoundary>
);
}

reset() calls onReset before remounting the children. Keep that callback synchronous. If recovery requires asynchronous work, perform and handle it in your custom fallback, then call reset() after it succeeds. Custom fallbacks own their wording, accessibility, and actions; a static node does not receive a retry function. Do not call reset() while rendering a fallback.

Report diagnostics without displaying them

Section titled “Report diagnostics without displaying them”

By default, the boundary keeps its existing console.error reporting. Supply onError to replace that reporter with your application’s approved logging or telemetry handler. This does not disable React’s own error reporting or any reporter configured on the React root.

Treat thrown values and component stacks as potentially sensitive. Sanitize them according to your application’s logging policy and never copy them into the fallback. The boundary does not pass diagnostics to the fallback callback or retain them in its fallback state.

Use composition through onError, onReset, and fallback instead of subclassing the boundary. Changing children or other props alone does not reset a failed boundary; retry explicitly, or change its React key to create a new boundary.

The boundary catches errors in descendant rendering, constructors, and lifecycle methods. It does not catch errors in:

  • Event handlers: use explicit error handling in the handler.
  • Asynchronous work: handle rejected promises and asynchronous callbacks.
  • Server-side rendering.
  • The boundary’s own render path, including a custom fallback. An ancestor boundary can catch render failures in that fallback.

Place boundaries around meaningful, independently recoverable sections. See Common components for other building blocks.