
500 page with a retry action, home link, collapsible technical details (request id, timestamp, copy button) and a system status line. Ships composable parts.
@hirael






























registry/hirael/bases/radix/blocks/error-01/error-01.tsx
// Error 01 from Hirael <https://hirael.com/blocks/not-found/error-01>
// MIT · Mohammad Shehadeh · https://github.com/MohammadShehadeh/hirael
'use client';
import * as React from 'react';
import { ChevronDown, RotateCw } from 'lucide-react';
import { cn } from '@/lib/utils';
import { Button } from '@/registry/hirael/bases/radix/ui/button';
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from '@/registry/hirael/bases/radix/ui/collapsible';
import { CopyButton } from '@/registry/hirael/bases/radix/components/copy-button';
import { Spinner } from '@/registry/hirael/bases/radix/ui/spinner';
const ENTER =
'animate-in fade-in slide-in-from-bottom-4 duration-500 ease-[cubic-bezier(0.22,1,0.36,1)] fill-mode-both motion-reduce:animate-none';
const stagger = (index: number): React.CSSProperties => ({ animationDelay: `${index * 60}ms` });
const ErrorPage = ({ className, ...props }: React.ComponentProps<'section'>) => {
return (
<section
data-slot="error-page"
className={cn('flex min-h-svh items-center justify-center bg-background py-20', className)}
{...props}
/>
);
};
const ErrorPageEyebrow = ({ className, ...props }: React.ComponentProps<'span'>) => {
return (
<span
data-slot="error-page-eyebrow"
className={cn('text-xs text-muted-foreground uppercase', className)}
{...props}
/>
);
};
const ErrorPageTitle = ({ className, ...props }: React.ComponentProps<'h1'>) => {
return (
<h1
data-slot="error-page-title"
className={cn('font-serif text-5xl leading-none font-medium tracking-tight sm:text-6xl md:text-7xl', className)}
{...props}
/>
);
};
const ErrorPageDescription = ({ className, ...props }: React.ComponentProps<'p'>) => {
return (
<p
data-slot="error-page-description"
className={cn('max-w-md text-base text-muted-foreground sm:text-lg', className)}
{...props}
/>
);
};
export interface ErrorPageActionsProps extends React.ComponentProps<'div'> {
/** Runs on "Try again". Defaults to reloading the page. */
onRetry?: () => void | Promise<void>;
retryLabel?: React.ReactNode;
homeHref?: string;
homeLabel?: React.ReactNode;
}
const ErrorPageActions = ({
onRetry,
retryLabel = 'Try again',
homeHref = '/',
homeLabel = 'Go home',
className,
children,
...props
}: ErrorPageActionsProps) => {
const [retrying, setRetrying] = React.useState(false);
const retry = React.useCallback(async () => {
if (onRetry) {
setRetrying(true);
try {
await onRetry();
} finally {
setRetrying(false);
}
return;
}
if (typeof window !== 'undefined') window.location.reload();
}, [onRetry]);
return (
<div data-slot="error-page-actions" className={cn('flex flex-wrap items-center gap-3', className)} {...props}>
<Button type="button" size="lg" onClick={() => void retry()} disabled={retrying}>
{retrying ? <Spinner className="motion-reduce:animate-none" /> : <RotateCw className="size-4" />}
{retryLabel}
</Button>
<Button asChild variant="outline" size="lg">
<a href={homeHref}>{homeLabel}</a>
</Button>
{children}
</div>
);
};
export interface ErrorPageDetailsProps extends React.ComponentProps<'div'> {
requestId: string;
/** ISO 8601 string or preformatted text. */
timestamp: string;
/** Extra label/value rows shown after Request ID and Timestamp. */
rows?: ReadonlyArray<{ label: string; value: string }>;
defaultOpen?: boolean;
}
const ErrorPageDetails = ({
requestId,
timestamp,
rows = [],
defaultOpen = false,
className,
...props
}: ErrorPageDetailsProps) => {
const allRows = React.useMemo(
() => [{ label: 'Request ID', value: requestId }, { label: 'Timestamp', value: timestamp }, ...rows],
[requestId, timestamp, rows],
);
const copyText = React.useMemo(() => allRows.map((r) => `${r.label}: ${r.value}`).join('\n'), [allRows]);
return (
<Collapsible defaultOpen={defaultOpen} asChild>
<div data-slot="error-page-details" className={cn('w-full border-t border-border pt-4', className)} {...props}>
<CollapsibleTrigger asChild>
<button
type="button"
className="group inline-flex items-center gap-2 rounded-sm text-xs text-muted-foreground uppercase transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
>
<ChevronDown className="size-3.5 transition-transform duration-150 group-data-[state=open]:rotate-180 motion-reduce:transition-none" />
Technical details
</button>
</CollapsibleTrigger>
<CollapsibleContent className="data-[state=open]:animate-in data-[state=open]:duration-250 data-[state=open]:ease-[cubic-bezier(0.22,1,0.36,1)] data-[state=open]:fade-in data-[state=open]:slide-in-from-top-1 motion-reduce:animate-none">
<div className="mt-3 flex flex-col gap-3 rounded-sm border border-border bg-card p-4">
<dl className="flex flex-col gap-2">
{allRows.map((row) => (
<div
key={row.label}
data-slot="error-page-details-row"
className="flex flex-wrap items-baseline justify-between gap-x-4 gap-y-1 text-xs"
>
<dt className="text-muted-foreground uppercase">{row.label}</dt>
<dd dir="ltr" className="text-foreground tabular-nums select-all">
{row.value}
</dd>
</div>
))}
</dl>
<div className="flex justify-end border-t border-border pt-3">
<CopyButton value={copyText} variant="outline" size="sm">
Copy details
</CopyButton>
</div>
</div>
</CollapsibleContent>
</div>
</Collapsible>
);
};
export interface ErrorPageStatusProps extends React.ComponentProps<'a'> {
tone?: 'success' | 'warning' | 'destructive';
}
const ErrorPageStatus = ({ tone = 'success', className, children, ...props }: ErrorPageStatusProps) => {
const dot = tone === 'warning' ? 'bg-warning' : tone === 'destructive' ? 'bg-destructive' : 'bg-success';
return (
<a
data-slot="error-page-status"
data-tone={tone}
className={cn(
'inline-flex items-center gap-2 rounded-sm text-xs text-muted-foreground uppercase transition-colors hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none',
className,
)}
{...props}
>
<span aria-hidden className={cn('size-1.5 rounded-full', dot)} />
{children}
</a>
);
};
const REQUEST_ID = 'req_8f2a1c9e4b7d';
const TIMESTAMP = '2026-08-26T14:32:07.412Z';
const Error01 = () => {
return (
<ErrorPage data-slot="error-01-block">
<div className="mx-auto w-full max-w-2xl px-6 md:px-10">
<div className="flex flex-col items-start gap-6">
<ErrorPageEyebrow className={ENTER}>500</ErrorPageEyebrow>
<ErrorPageTitle style={stagger(1)} className={ENTER}>
Something broke on our end.
</ErrorPageTitle>
<ErrorPageDescription style={stagger(2)} className={ENTER}>
The request hit an error we didn't expect. It's been logged, and retrying usually works. If it
keeps happening, send us the details below.
</ErrorPageDescription>
<ErrorPageActions
style={stagger(3)}
className={ENTER}
homeHref="#"
onRetry={() => new Promise((r) => setTimeout(r, 900))}
/>
<ErrorPageDetails
style={stagger(4)}
className={ENTER}
requestId={REQUEST_ID}
timestamp={TIMESTAMP}
rows={[
{ label: 'Route', value: 'GET /api/projects/prj_41/deploys' },
{ label: 'Region', value: 'fra1' },
]}
/>
<ErrorPageStatus style={stagger(5)} className={ENTER} href="#">
Status: all systems operational
</ErrorPageStatus>
</div>
</div>
</ErrorPage>
);
};
export {
ErrorPage,
ErrorPageEyebrow,
ErrorPageTitle,
ErrorPageDescription,
ErrorPageActions,
ErrorPageDetails,
ErrorPageStatus,
};
export default Error01;