openstatus
blockstatus-blanksource: ok · hit
Status Blank States
Empty and skeleton state components for loading and no-data scenarios
npx shadcn add "https://openstatus.dev/r/status-blank.json"free
Where it goes
stats
Interaction
animated-counter
Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.
Files1 · source cached 10/14/2026, 3:35:58 PM
src/components/blocks/status-blank.tsx
"use client";
import { useStatusBlocksLabels } from "@/components/blocks/status-i18n";
import { cn } from "@/lib/utils";
// ============================================================================
// Container Components
// ============================================================================
/**
* StatusBlankContainer - Main container for empty state displays
*
* Provides a centered, bordered container with muted background for displaying
* empty state content. The container is responsive with adaptive padding
* (sm:px-8 sm:py-6) and uses flexbox for vertical centering of content.
*
* @example
* ```tsx
* <StatusBlankContainer>
* <StatusBlankTitle>No Data Available</StatusBlankTitle>
* <StatusBlankDescription>Add monitors to see data here</StatusBlankDescription>
* </StatusBlankContainer>
* ```
*
* @see StatusBlankTitle - For heading text
* @see StatusBlankDescription - For descriptive text
*/
export function StatusBlankContainer({
children,
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
className={cn(
"bg-muted/30 flex flex-col items-center justify-center gap-2.5 rounded-lg border px-3 py-2 text-center sm:px-8 sm:py-6",
className,
)}
{...props}
>
{children}
</div>
);
}
// ============================================================================
// Text Components
// ============================================================================
/**
* StatusBlankTitle - Title text for empty state displays
*
* Displays medium-weight title text within empty state containers.
* Typically used to communicate the empty state condition.
*
* @example
* ```tsx
* <StatusBlankTitle>No monitors found</StatusBlankTitle>
* ```
*
* @see StatusBlankDescription - For additional descriptive text
*/
export function StatusBlankTitle({
children,
className,
...props
}: React.ComponentProps<"div">) {
return (
<div className={cn("font-medium", className)} {...props}>
{children}
</div>
);
}
/**
* StatusBlankDescription - Descriptive text for empty state displays
*
* Displays muted, monospaced text providing additional context or guidance
* for the empty state. The monospace font helps distinguish it as secondary
* instructional text.
*
* @example
* ```tsx
* <StatusBlankDescription>
* Add monitors to this page to see their status here
* </StatusBlankDescription>
* ```
*
* @see StatusBlankTitle - For primary heading text
*/
export function StatusBlankDescription({
children,
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
className={cn("text-muted-foreground font-mono text-sm", className)}
{...props}
>
{children}
</div>
);
}
/**
* StatusBlankContent - Content wrapper for empty state text
*
* Provides vertical spacing (space-y-1) for stacking title and description
* components within an empty state display.
*
* @example
* ```tsx
* <StatusBlankContent>
* <StatusBlankTitle>No Events</StatusBlankTitle>
* <StatusBlankDescription>No events to display</StatusBlankDescription>
* </StatusBlankContent>
* ```
*/
export function StatusBlankContent({
children,
className,
...props
}: React.ComponentProps<"div">) {
return (
<div className={cn("space-y-1", className)} {...props}>
{children}
</div>
);
}
// ============================================================================
// Visualization Components
// ============================================================================
/**
* StatusBlankReport - Visual representation of an empty incident report
*
* Displays a stylized preview of an incident report page with placeholder
* header, report updates, and an overlay gradient. Used to visualize what
* incident reports will look like when created.
*
* This component is typically rendered in multiple layers with different
* scales and opacities to create a stacked card effect.
*
* @example
* ```tsx
* <div className="relative">
* <StatusBlankReport className="absolute scale-80 opacity-80" />
* <StatusBlankReport />
* </div>
* ```
*
* @see StatusBlankEvents - For composed empty state with stacked reports
* @see StatusBlankPageHeader - For the header visualization
* @see StatusBlankReportUpdate - For the update line visualizations
*/
export function StatusBlankReport({ ...props }: React.ComponentProps<"div">) {
return (
<StatusBlankPage {...props}>
<StatusBlankPageHeader />
<div className="flex w-full flex-col">
<StatusBlankReportUpdate />
<StatusBlankReportUpdate />
</div>
<StatusBlankOverlay />
</StatusBlankPage>
);
}
/**
* StatusBlankMonitor - Visual representation of an empty monitor display
*
* Displays a stylized preview of a monitor page with placeholder header and
* uptime visualization bars. Used to show what monitor displays will look like
* when monitors are added.
*
* This component is typically rendered in multiple layers with different
* scales and opacities to create a stacked card effect.
*
* @example
* ```tsx
* <div className="relative">
* <StatusBlankMonitor className="absolute scale-80 opacity-80" />
* <StatusBlankMonitor />
* </div>
* ```
*
* @see StatusBlankMonitors - For composed empty state with stacked monitors
* @see StatusBlankPageHeader - For the header visualization
* @see StatusBlankMonitorUptime - For the uptime bar visualization
*/
export function StatusBlankMonitor({ ...props }: React.ComponentProps<"div">) {
return (
<StatusBlankPage {...props}>
<StatusBlankPageHeader />
<StatusBlankMonitorUptime />
<StatusBlankOverlay />
</StatusBlankPage>
);
}
// ============================================================================
// Animation Components (for visualization internals)
// ============================================================================
/**
* StatusBlankPage - Base container for blank page visualizations
*
* Provides a card-like container with border and background for page previews.
* This component is used as the foundation for StatusBlankReport and
* StatusBlankMonitor visualizations, providing consistent sizing and styling.
*
* The container uses relative positioning to enable absolutely positioned
* overlay gradients within the visualization.
*
* @example
* ```tsx
* <StatusBlankPage>
* <StatusBlankPageHeader />
* <div>// Content here</div>
* <StatusBlankOverlay />
* </StatusBlankPage>
* ```
*
* @see StatusBlankReport - For report visualization using this container
* @see StatusBlankMonitor - For monitor visualization using this container
*/
export function StatusBlankPage({
className,
children,
...props
}: React.ComponentProps<"div">) {
return (
<div
className={cn(
"border-border/70 bg-background relative flex w-full max-w-xs flex-1 flex-col items-center justify-center gap-4 overflow-hidden rounded-lg border px-3 py-2 text-center",
className,
)}
{...props}
>
{children}
</div>
);
}
/**
* StatusBlankPageHeader - Placeholder header for page visualizations
*
* Displays a stylized representation of a page header with placeholder elements
* for logo, navigation items, and actions. Uses accent-colored rounded rectangles
* to create a recognizable header pattern.
*
* The header shows:
* - Left: Single square (logo placeholder)
* - Center: Three rectangles (navigation items)
* - Right: Single rectangle (action button)
*
* @example
* ```tsx
* <StatusBlankPage>
* <StatusBlankPageHeader />
* // Other visualization content
* </StatusBlankPage>
* ```
*/
export function StatusBlankPageHeader({
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
className={cn(
"flex w-full items-center justify-between gap-4",
className,
)}
{...props}
>
<div className="bg-accent/60 size-3 rounded-sm" />
<div className="flex flex-row gap-1">
<div className="bg-accent/60 h-3 w-8 rounded-sm" />
<div className="bg-accent/60 h-3 w-8 rounded-sm" />
<div className="bg-accent/60 h-3 w-8 rounded-sm" />
</div>
<div className="bg-accent/60 h-3 w-8 rounded-sm" />
</div>
);
}
/**
* StatusBlankMonitorUptime - Uptime visualization for monitor previews
*
* Displays a stylized uptime chart with placeholder labels and 30 vertical bars
* representing uptime data. Some bars have varying heights to create a realistic
* visualization pattern showing occasional incidents.
*
* The visualization includes:
* - Top: Three placeholder labels for time periods
* - Bottom: 30 vertical bars with most at full height and some shorter to indicate incidents
*
* @example
* ```tsx
* <StatusBlankMonitor>
* <StatusBlankPageHeader />
* <StatusBlankMonitorUptime />
* </StatusBlankMonitor>
* ```
*/
export function StatusBlankMonitorUptime({
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
className={cn(
"flex w-full flex-col items-center justify-between gap-1",
className,
)}
{...props}
>
<div className="flex w-full flex-row gap-1">
<div className="bg-accent h-3 w-8 rounded-sm" />
<div className="bg-accent h-3 w-12 rounded-sm" />
<div className="bg-accent h-3 w-10 rounded-sm" />
</div>
<div className="flex w-full flex-row items-end gap-0.5">
{Array.from({ length: 30 }).map((_, index) => (
<div
key={index}
className={cn(
"bg-accent h-12 flex-1 rounded-sm",
[10, 20].includes(index) && "h-8",
[25].includes(index) && "h-10",
)}
/>
))}
</div>
</div>
);
}
/**
* StatusBlankReportUpdate - Single update entry for report visualizations
*
* Displays a stylized representation of an incident report update with placeholder
* elements for status indicator, timestamp, and message lines. Creates a timeline-like
* appearance when stacked vertically.
*
* The update shows:
* - Left: Square status indicator
* - Right: Two label placeholders (status + timestamp) and two message lines
*
* @example
* ```tsx
* <StatusBlankPage>
* <StatusBlankPageHeader />
* <div className="flex flex-col">
* <StatusBlankReportUpdate />
* <StatusBlankReportUpdate />
* </div>
* </StatusBlankPage>
* ```
*/
export function StatusBlankReportUpdate({
className,
...props
}: React.ComponentProps<"div">) {
return (
<div className={cn("flex w-full items-start gap-2", className)} {...props}>
<div className="flex h-full flex-col items-center gap-0.5">
<div className="bg-accent size-3 rounded-sm" />
</div>
<div className="flex flex-1 flex-col gap-1 pb-2">
<div className="flex items-center gap-1">
<div className="bg-accent h-3 w-12 rounded-sm" />
<div className="bg-accent h-3 w-16 rounded-sm" />
</div>
<div className="bg-accent h-3 w-full rounded-sm" />
<div className="bg-accent h-3 w-full rounded-sm" />
</div>
</div>
);
}
/**
* StatusBlankOverlay - Gradient overlay for page visualizations
*
* Provides a bottom-to-top gradient overlay that fades the visualization content
* from transparent (top 40%) to background color (bottom), creating a subtle
* depth effect. The overlay is absolutely positioned to cover the entire parent.
*
* This overlay helps create visual separation between the preview visualization
* and any content that might be displayed on top of it (like call-to-action text).
*
* @example
* ```tsx
* <StatusBlankPage>
* <StatusBlankPageHeader />
* <StatusBlankMonitorUptime />
* <StatusBlankOverlay />
* </StatusBlankPage>
* ```
*/
export function StatusBlankOverlay({
children,
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
className={cn(
"to-background absolute inset-0 flex flex-col items-center justify-center gap-2 bg-gradient-to-b from-transparent from-40% p-2",
className,
)}
{...props}
>
{children}
</div>
);
}
// ============================================================================
// Composed Empty States
// ============================================================================
/**
* StatusBlankEvents - Complete empty state for incident reports
*
* Displays a fully composed empty state with stacked StatusBlankReport
* visualizations (three layers with varying scales and opacities) and
* customizable title/description text. This creates an engaging empty state
* that shows users what incident reports will look like.
*
* The visualization uses absolute positioning to create a layered card stack
* effect with the front card at full opacity and back cards progressively
* faded and scaled down.
*
* @param title - The empty state heading (defaults to `labels.noReports` from the i18n provider)
* @param description - The empty state description (defaults to `labels.noReportsDescription` from the i18n provider)
*
* @example
* ```tsx
* <StatusBlankEvents
* title="No incidents yet"
* description="Incident reports will appear here when created"
* />
* ```
*
* @see StatusBlankReport - For the underlying report visualization
*/
export function StatusBlankEvents({
title,
description,
action,
...props
}: React.ComponentProps<typeof StatusBlankContainer> & {
title?: string;
description?: string;
action?: React.ReactNode;
}) {
const labels = useStatusBlocksLabels();
return (
<StatusBlankContainer {...props}>
<div className="relative mt-8 flex w-full flex-col items-center justify-center">
<StatusBlankReport className="absolute -top-16 scale-60 opacity-50" />
<StatusBlankReport className="absolute -top-8 scale-80 opacity-80" />
<StatusBlankReport />
</div>
<StatusBlankContent>
<StatusBlankTitle>{title ?? labels.noReports}</StatusBlankTitle>
<StatusBlankDescription>
{description ?? labels.noReportsDescription}
</StatusBlankDescription>
</StatusBlankContent>
{action}
</StatusBlankContainer>
);
}
/**
* StatusBlankMonitors - Complete empty state for monitors
*
* Displays a fully composed empty state with stacked StatusBlankMonitor
* visualizations (three layers with varying scales and opacities) and
* customizable title/description text. This creates an engaging empty state
* that shows users what monitor displays will look like.
*
* The visualization uses absolute positioning to create a layered card stack
* effect with the front card at full opacity and back cards progressively
* faded and scaled down.
*
* @param title - The empty state heading (defaults to `labels.noPublicMonitors` from the i18n provider)
* @param description - The empty state description (defaults to `labels.noPublicMonitorsDescription` from the i18n provider)
*
* @example
* ```tsx
* <StatusBlankMonitors
* title="No monitors configured"
* description="Add monitors to start tracking uptime"
* />
* ```
*
* @see StatusBlankMonitor - For the underlying monitor visualization
*/
export function StatusBlankMonitors({
title,
description,
action,
...props
}: React.ComponentProps<typeof StatusBlankContainer> & {
title?: string;
description?: string;
action?: React.ReactNode;
}) {
const labels = useStatusBlocksLabels();
return (
<StatusBlankContainer {...props}>
<div className="relative mt-8 flex w-full flex-col items-center justify-center">
<StatusBlankMonitor className="absolute -top-16 scale-60 opacity-50" />
<StatusBlankMonitor className="absolute -top-8 scale-80 opacity-80" />
<StatusBlankMonitor />
</div>
<StatusBlankContent>
<StatusBlankTitle>{title ?? labels.noPublicMonitors}</StatusBlankTitle>
<StatusBlankDescription>
{description ?? labels.noPublicMonitorsDescription}
</StatusBlankDescription>
</StatusBlankContent>
{action}
</StatusBlankContainer>
);
}
/**
* StatusBlankAction - Styled wrapper for empty-state CTAs.
*
* Applies border + hover chrome around any actionable child (link, button).
* Pass a bare `<Link>` or `<button>` — this component owns the look. Consumers
* of `StatusBlankEvents`/`StatusBlankMonitors`/`StatusFeed.emptyAction` must
* wrap their action in this themselves; the parents render the action raw to
* avoid doubling chrome on already-styled controls.
*/
export function StatusBlankAction({
children,
className,
...props
}: React.ComponentProps<"div">) {
return (
<div
data-slot="status-blank-action"
className={cn(
"border-border/70 text-muted-foreground hover:border-border hover:text-foreground mt-2 inline-flex items-center justify-center rounded-md border px-3 py-1.5 font-mono text-sm [&>a]:text-inherit [&>a]:no-underline",
className,
)}
{...props}
>
{children}
</div>
);
}