Shadcn Error State Table
A failed fetch shown two ways: a full error panel when there is nothing to display, and an inline banner above the last loaded rows when stale data is still useful. Both come with a retry action.
$ npx shadcn add https://www.shad-table.dev/r/error-state-table.json| Customer | Status | Amount | Due |
|---|---|---|---|
Something went wrong Request failed with status 503. Check your connection and try again. | |||
How it works
1.The error shape depends on whether data exists
If rows are already on screen, a failed refresh shouldn't wipe them: the table keeps the stale rows and shows a banner above. If there is nothing to show, the error takes the place of the table body. One hasStaleData check picks between them.
const hasStaleData = rows.length > 0{error && hasStaleData && <ErrorState variant="banner" ... />}// ...no rows:{error ? <ErrorState title="Something went wrong" ... /> : null}
2.One component, two variants
ErrorState renders a centered panel by default and a compact horizontal banner with variant="banner". They share the same retry button and wording props, so the message stays consistent wherever it appears.
export function ErrorState({title, description, onRetry, isRetrying = false,variant = 'panel', // 'panel' | 'banner'}: ErrorStateProps)
3.Retry shows its own progress
While a retry is in flight the button is disabled, its icon spins, and its label changes to "Retrying...". That prevents duplicate requests and tells the user something is happening.
<Button variant="outline" size="sm" onClick={onRetry} disabled={isRetrying}><RotateCw className={cn(isRetrying && 'animate-spin')} />{isRetrying ? 'Retrying...' : 'Try again'}</Button>
4.role="alert" announces the failure
Both variants use role="alert", so screen readers announce the error when it appears instead of leaving the user waiting on a table that will never fill.
<div role="alert" className="...">