1. Documentation
  2. Status page UI
  3. StatusPage component
ReadmenpmGitHub
  • Introduction
  • Quickstart
  • Configuration file
  • Monitors
  • Checks and scheduling
  • Notifications
  • Incidents and maintenance
  • Subscribers
  • Metrics and badges
  • Identity and appearance
  • Telemetry
  • The check run
  • Uptime and history
  • Automatic incidents
  • Notification delivery
  • Public subscriptions
  • StatusPage component
  • Themes
  • UI primitives
  • Colour mode
  • React Router
  • Next.js
  • Astro
  • SQLite
  • Cloudflare D1
  • PostgreSQL
  • Schema and migrations
  • Cloudflare Workers
  • Vercel
  • Self-hosting
  • API overview
  • Status endpoints
  • Incident and maintenance endpoints
  • Subscriber endpoints
  • Badges, feeds and metrics
  • Admin endpoints
  • CLI commands
  • Package exports
  • Security
  • Troubleshooting

StatusPage component

The data-only page component, its props and what the shell owns.

<StatusPage /> renders a complete status page from one snapshot. It owns everything that is not visual — colour mode, brand tokens, monitor grouping and the lazily mounted subscribe dialog — and hands the result to the configured theme, which is the only thing that decides how the page looks.

tsx
import { StatusPage } from "@heyo-sh/heyo-status/ui";import "@heyo-sh/heyo-status/theme/status.css";import { statusPage } from "../heyo-status.config";const snapshot = await statusPage.api.getSnapshot();<StatusPage  basePath={statusPage.basePath}  branding={statusPage.branding}  colors={statusPage.colors}  metrics={statusPage.metrics}  mode={statusPage.mode}  snapshot={snapshot}  subscribersEnabled={statusPage.subscribers.enabled}  subscriberMethods={statusPage.subscribers.methods}  theme={statusPage.theme}  title={statusPage.title}/>;

Passing configuration-derived values keeps one decision in one place: change theme or branding in heyo-status.config.ts and the page follows.

Props

snapshotStatusSnapshotrequired

The payload from statusPage.api.getSnapshot() or GET /status.

titlestringoptional

Defaults to "Heyo Status". Used for accessible labelling, not as visible header text.

brandingResolvedStatusBrandingoptional

{ logo?, name? }. Controls the header mark and its optional label.

theme"slate" | "fern" | "onyx" | "dune" | "reed"optional

Defaults to "slate". Selects the layout and publishes data-theme.

mode"system" | "light" | "dark"optional

Defaults to "system". The initial colour-mode preference.

colors{ primary?: string; secondary?: string }optional

Published as CSS custom properties on the page container.

metricsStatusMetricsOptionsoptional

showLatency, showLatencyChart, showUptimePercent, uptimePeriods.

basePathstringoptional

Defaults to "/api/heyo-status". Feed and subscription URLs are derived from it.

rssHrefstringoptional

Defaults to `${basePath}/rss.xml`.

subscribersEnabledbooleanoptional

Defaults to false. Shows the subscribe control.

subscriberMethods("email" | "rss" | "webhook")[]optional

Which tabs the built-in dialog offers.

subscribeHrefstringoptional

Link to your own subscribe page instead of opening the dialog.

subscriberApiUrlstringoptional

Overrides the base-path-derived POST target of the dialog.

onSubscribeMouseEventHandler<HTMLButtonElement>optional

Take over the button entirely.

showPoweredBybooleanoptional

Defaults to true.

classNamestringoptional

Added to the page container.

Server rendering

The component is "use client", but it renders fully on the server. All the page's primary content — overall status, monitor cards, uptime grids, incident timelines, maintenance windows — is static markup. Incident disclosures and monitor groups are native <details> elements, so they still open when the bundle fails to load, which is exactly when people come looking for a status page.

Only two things need JavaScript: the colour-mode toggle and the subscribe dialog. The dialog is lazy()-imported on first use, because its modal, tabs and form are more component code than the rest of the page put together.

Load the snapshot on the server

Every framework template awaits statusPage.api.getSnapshot() in a loader, a server component or Astro frontmatter. Fetching it from the browser would make the first paint an empty page and send the database read on the critical path.

Framework placement

export const dynamic = "force-dynamic";export default async function Page() {  const { statusPage } = await import("../heyo-status.config");  const snapshot = await statusPage.api.getSnapshot();  return <StatusPage snapshot={snapshot} theme={statusPage.theme} />;}

Astro needs client:load: without it the toggle and the dialog render as inert markup.

Rendering a remote snapshot

The snapshot is plain JSON, so a page can live in a different application from the monitoring runtime:

tsx
const response = await fetch("https://status.acme.com/api/heyo-status/status");const snapshot = reviveDates(await response.json());<StatusPage snapshot={snapshot} basePath="https://status.acme.com/api/heyo-status" />;

Dates arrive as ISO strings over HTTP. Revive them before rendering, or use the primitives that accept Date | string directly.

Related

  • Themes
  • UI primitives
  • Colour mode
Public subscriptions< PreviousThemesNext >

Powered by heyo

On this page

PropsServer renderingFramework placementRendering a remote snapshot