ErrorState

A surface for failed-fetch / failed-action states. Visually mirrors Empty but with destructive bias and an optional retry button. Mounts with role='alert' so screen readers announce on first render.

Fetch failure (default tone, recoverable)

Hard failure (destructive tone, unrecoverable)

Installation

pnpm
pnpm dlx @hex-core/cli add error-state

Hard failure (destructive)

Server returned 5xx and we want to alarm

tsx
<ErrorState
  icon={<XCircleIcon />}
  variant="destructive"
  title="Sync failed"
  message="We couldn't save your changes. They're still on this device — refresh to retry."
/>

Variant values

variantTone of the surface.
ValueDescription
defaultdefault
Muted neutral surface — for recoverable / transient failures.
destructive
Tinted destructive surface — for hard / unrecoverable failures.

API Reference

PropTypeDefaultDescription
icon
ReactNodeIcon (typically an alert / x-circle SVG).
title
ReactNodeSomething went wrongHeading copy. Falls back to a generic message.
messagerequired
ReactNodeBody copy explaining what failed and (optionally) what the user can do.
action
ReactNodeCall-to-action slot — typically a <Button onClick={refetch}>Retry</Button>. Consumer controls the button variant, loading state, and asChild composition.
variant
"default" | "destructive"defaultVisual tone — destructive draws more attention, default is calmer.

AI Guidance

When to use

Use for any failure surface where the user might benefit from context + a retry path. Pair with onRetry whenever the operation is genuinely retryable; omit it when the user has to take a different action (e.g. log in again).

When not to use

Don't use for inline form-field errors (Form's <FormMessage> handles those). Don't use for blocking destructive confirmations (AlertDialog). Don't use for transient toasts (Sonner / Toaster).

Common mistakes

  • Generic 'Something went wrong' message without context — at minimum, name what failed
  • Using destructive variant for recoverable network blips (cries wolf)
  • Wiring the action's click handler to a function that doesn't actually re-trigger the failed operation
  • Forgetting the action slot when the failure IS retryable — leaves the user stuck

Accessibility

role='alert' so screen readers announce on first render. Icon decorative (aria-hidden). Retry button uses focus-visible ring; pressing it doesn't dismiss the surface — caller controls that via state.

Token budget: 450