Error state
Says what went wrong and offers a single retry.
npx shadcn@latest add https://ui.goodtabs.co/r/error-state.json
With the @goodtabs namespace in components.json: npx shadcn@latest add @goodtabs/error-state
Could not load deploys
The smallest useful version.
With a reason
Sync failed
We could not reach the server. Your changes are saved on this device.
A description that changes after each retry.
Usage
import { ErrorState } from "@/components/ui/error-state"
<ErrorState title="Could not load deploys">
<Button onClick={retry}>Try again</Button>
</ErrorState>Props
| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | What went wrong, in plain words. | |
| description | string | Why it happened and what happens next. | |
| children | ReactNode | The one action, usually a retry button. |
Source
error-state/error-state.tsx
import * as React from "react";
import { TriangleAlertIcon } from "lucide-react";
import { cn } from "@/lib/utils";
type ErrorStateProps = Omit<React.ComponentProps<"div">, "title"> & {
/** What went wrong, in plain words. */
title: string;
/** Why, and what the person can expect. One or two sentences. */
description?: string;
};
/**
* What went wrong and one way forward. Pass a single retry button as the
* children. It announces itself as an alert when it appears.
*/
export function ErrorState({ title, description, className, children, ...props }: ErrorStateProps) {
return (
<div
role="alert"
data-slot="error-state"
className={cn("flex flex-col items-center gap-3 px-4 py-6 text-center", className)}
{...props}
>
<span className="flex size-9 items-center justify-center rounded-full border bg-muted text-foreground">
<TriangleAlertIcon className="size-4" aria-hidden="true" />
</span>
<div className="space-y-1">
<h3 className="text-sm font-medium text-foreground">{title}</h3>
{description && <p className="max-w-xs text-sm text-foreground/70">{description}</p>}
</div>
{children}
</div>
);
}
For AI agents
Hand your agent this page, the markdown at /components/error-state/prompt.md, or the Copy AI prompt button above.
When to use
- A region failed to load and retrying can help
- Replacing the content of a card, table or panel, not the whole page
When not to use
- Field validation, which belongs next to the field
- Errors the person cannot act on, where plain text is enough
Agent notes
- Renders role=alert, so mount it when the error happens rather than hiding it
- Stays monochrome on purpose: the icon and the words carry the meaning, not a red fill
- Pass one action. Two buttons turn a retry into a decision
- Add the border and radius through className when you place it inside a card