# Status Pages

> Public status screens: an overview with a health banner, grouped components on 90-day uptime bars with day tooltips and an expandable incident history, and a live incident page with a stage stepper, streaming timeline and error-rate sparkline.

- Collection: Pages
- Tier: pro
- Docs: https://geturui.com/docs/status-pages
- Install: `npx shadcn@latest add @geturui-pro/status-pages`
- Dependencies: motion, lucide-react

## Variants

### Overview

Health banner, collapsible component groups with 90 / 60 / 30-day uptime bars (by container width), expandable incident history and an email subscribe form.

Install: `npx shadcn@latest add @geturui-pro/status-pages-overview`

```tsx
import { StatusOverview } from "@/components/pages/status-pages/overview";

export default async function Status() {
  const { groups, incidents } = await getStatus();
  return <StatusOverview productName="Acme" groups={groups} incidents={incidents} asOf="2026-09-29" onSubscribe={(email) => subscribe(email)} />;
}
```

| Prop | Type | Default | Description |
|---|---|---|---|
| productName | `string` | "Kestrel" | Header title. |
| groups | `{ name; components: { id; name; description?; status; history? }[] }[]` | — | Component groups. history is daily uptime 0–1, oldest first; generated deterministically when omitted. |
| incidents | `{ id; date; title; impact; duration; updates }[]` | — | Past incidents, newest first. |
| asOf | `string` | "2026-09-29" | Last day on the bars (YYYY-MM-DD). |
| days | `number` | 90 | Days of generated history. |
| onSubscribe | `(email: string) => void | Promise<void>` | — | Subscribe handler. Throw to show an error. |
| className | `string` | — | Classes for the outer container. |

### Incident response

Live incident page: severity, a ticking duration, a four-stage stepper, a timeline where scripted and posted updates spring in, an impact panel and a live error-rate sparkline.

Install: `npx shadcn@latest add @geturui-pro/status-pages-incident-response`

```tsx
import { IncidentResponse } from "@/components/pages/status-pages/incident-response";

export default function Incident({ incident }) {
  return (
    <IncidentResponse
      title={incident.title}
      severity="SEV1"
      updates={incident.updates}
      scripted={[]}
      onPostUpdate={({ stage, body }) => api.incidents.post(incident.id, { stage, body })}
    />
  );
}
```

| Prop | Type | Default | Description |
|---|---|---|---|
| title | `string` | — | Incident title. |
| severity | `"SEV1" | "SEV2" | "SEV3"` | "SEV2" | Severity pill. |
| startedSecondsAgo | `number` | 4334 | Seeds the duration clock. |
| startedAtMinutes | `number` | 820 | Start time in minutes after midnight UTC; stamps new updates. |
| updates | `{ id; stage; time; body; author? }[]` | — | Existing updates, newest first. The newest sets the current stage. |
| components | `{ name; impact: "degraded" | "partial" | "major" }[]` | — | Impacted components. |
| responders | `string[]` | — | Responder names. |
| scripted | `(update & { delay: number })[]` | — | Updates that arrive on their own after delay ms. Pass [] for real data. |
| canPost | `boolean` | true | Show the responder composer. |
| onPostUpdate | `(u: { stage; body }) => void | Promise<void>` | — | Publishes an update. Throw to show an error. |
| onSubscribeChange | `(subscribed: boolean) => void` | — | Get-updates toggle handler. |
| className | `string` | — | Classes for the outer container. |

## Accessibility

- Status is always given as a word and an icon, never colour alone.
- Uptime bars are one tab stop per row with arrow, Home and End keys; each day has a full aria-label and the tooltip follows focus.
- Incident updates and stage changes are announced politely; pulsing and morphing motion stops under reduced motion.

## Source

Pro item — send `Authorization: Bearer <registry token>` to include the source.
