1. Documentation
  2. Status page UI
  3. UI primitives
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

UI primitives

The components every bundled theme is composed from, and how to build your own page.

@heyo-sh/heyo-status/ui exports the components the bundled themes are built from. Use them to assemble a page that does not match any bundled layout, or to embed a single piece of a status page somewhere else.

tsx
import {  ActiveIncidents,  DarkModeToggle,  DayGrid,  IncidentTimeline,  LatencyChart,  MonitorCard,  MonitorGroup,  OverallStatus,  ScheduledMaintenance,  SectionHeading,  StatusBanner,  StatusFooter,  StatusHeader,  StatusShell,  UptimeBar,  formatTimestamp,} from "@heyo-sh/heyo-status/ui";

Layout

StatusShell{ theme, children, className? }optional

The page container. Publishes data-slot="status-page" and data-theme, and applies the theme's max-width token. Every layout renders into it.

StatusHeader{ branding, title?, subscribersEnabled?, subscribeHref?, onSubscribe?, className? }optional

Header chrome: brand mark, optional label, colour-mode toggle and the subscribe control.

StatusFooter{ generatedAt, rssHref?, showPoweredBy?, className? }optional

generatedAt accepts a Date or an ISO string, so a snapshot fetched over HTTP can be rendered without reviving it.

SectionHeading{ children, className? }optional

The quiet uppercase label shared by every bundled theme.

Status

OverallStatus{ status, className? }optional

The announced high-level state as a card, with a live indicator. aria-live="polite".

StatusBanner{ status, caption?, className? }optional

The same announcement as a tinted banner, for themes that lead with one global verdict.

MonitorCard{ monitor, metrics?, className? }optional

One monitor: name, description, latest state and latency, the day grid, the uptime meters and the sparkline — filtered by metrics.

MonitorGroup{ group, monitors, metrics?, defaultOpen?, className? }optional

A group rendered as a native <details> disclosure, so it stays usable without JavaScript.

UptimeBar{ label, uptime, className? }optional

A labelled meter that renders No data for null instead of 0%.

History

DayGrid{ days, monitorName, className? }optional

The uptime history bar: one flexed column per day, each carrying its aggregate in a native tooltip, so ninety days fit a phone with no horizontal scroller.

LatencyChart{ samples, monitorName, label?, className? }optional

The latency sparkline, drawn from monitor.latencySeries.

Incidents and maintenance

ActiveIncidents{ incidents, now?, className? }optional

Every active incident as a disclosure list.

IncidentDisclosure{ incident, now?, defaultOpen?, className? }optional

One incident with its timeline, anchored at #incident-<id> — the anchor the RSS and Atom entries link to.

IncidentTimeline{ updates, className? }optional

A chronological update list with semantic status labels.

ScheduledMaintenance{ maintenance, now?, className? }optional

Upcoming and in-progress windows with their scheduled range.

Utilities

DarkModeToggle{ className? }optional

Switches the persisted preference. Must be inside StatusThemeProvider.

formatTimestamp(value: Date | string) => stringoptional

The UTC formatting used across the page, so server and client markup always agree.

resolveStatusTheme(name: StatusThemeName) => HeyoStatusThemeoptional

Resolves a theme name to its { name, Layout } implementation.

Building a custom page

tsx
import {  ActiveIncidents,  MonitorCard,  OverallStatus,  SectionHeading,  StatusFooter,  StatusHeader,  StatusShell,} from "@heyo-sh/heyo-status/ui";import { StatusThemeProvider } from "@heyo-sh/heyo-status/theme/provider";import "@heyo-sh/heyo-status/theme/status.css";export function CustomStatusPage({ snapshot, metrics }) {  return (    <StatusThemeProvider defaultTheme="system">      <StatusShell theme="slate">        <StatusHeader branding={{ logo: "/logo.svg", name: "Acme" }} />        <OverallStatus status={snapshot.overall} />        {snapshot.activeIncidents.length > 0 ? (          <>            <SectionHeading>Active incidents</SectionHeading>            <ActiveIncidents incidents={snapshot.activeIncidents} />          </>        ) : null}        <SectionHeading>Services</SectionHeading>        {snapshot.monitors.map((monitor) => (          <MonitorCard key={monitor.name} metrics={metrics} monitor={monitor} />        ))}        <StatusFooter generatedAt={snapshot.generatedAt} rssHref="/api/heyo-status/rss.xml" />      </StatusShell>    </StatusThemeProvider>  );}

Keep StatusShell even in a custom page: it is what publishes data-theme and the data-slot="status-page" hook that project-level CSS targets.

The subscribe dialog

It is deliberately not re-exported from /ui:

tsx
import { SubscribeDialog } from "@heyo-sh/heyo-status/ui/subscribe-dialog";

A static re-export would always beat the dynamic import <StatusPage /> uses, pinning roughly 95 KB of modal, tabs and form code into the first chunk of every page — more than the rest of the status page put together. Import it from its own path, ideally lazily.

openbooleanrequired
onOpenChange(open: boolean) => voidoptional
methods("email" | "rss" | "webhook")[]optional

Which tabs to offer. Defaults to all three.

basePathstringoptional

Defaults to "/api/heyo-status".

apiUrlstringoptional

Overrides the derived POST target.

rssHref / atomHrefstringoptional

Feed links shown on the RSS tab.

Related

  • Themes and data-slot hooks
  • StatusPage props
  • Package exports
Themes< PreviousColour modeNext >

Powered by heyo

On this page

LayoutStatusHistoryIncidents and maintenanceUtilitiesBuilding a custom pageThe subscribe dialog