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

Themes

The five bundled layouts, the one stylesheet, and how to override them.

Five layouts ship with Heyo Status. theme in heyo-status.config.ts is the only switch: one stylesheet carries every theme's tokens, scoped to the data-theme attribute the page publishes, so changing a theme never changes an import.

heyo-status.config.ts
theme: "slate",
root layout
import "@heyo-sh/heyo-status/theme/status.css";

The layouts

ThemeLayout
slateDefault: grouped cards, daily uptime bars, latency sparklines.
fernOne uptime figure per service over a dense 90-day history.
onyxA global banner, a flat component list, a dated incident timeline.
duneA directory of service categories with per-subcomponent status rows.
reedMinimal: a narrow single column, no cards, no badges, no groups.

Pick by how your services are shaped. A handful of grouped services reads best in slate or dune; a long flat list belongs in onyx; a single product with a long history suits fern; reed is for a page that should look like a sentence rather than a dashboard.

One stylesheet

ts
import "@heyo-sh/heyo-status/theme/status.css";

It pulls in Tailwind, the heyo-ui tokens, the status-specific tokens and every bundled theme's token block. The per-theme theme/<name>.css paths still exist as compatibility aliases, but they resolve to the same file — there is no "wrong stylesheet" to import any more.

This matters because the tokens used to live at :root in five separate stylesheets, which quietly split one decision in two: theme chose the layout while the imported stylesheet chose the page width and radius scale. Changing theme moved the layout and left the width behind. Scoping tokens to [data-theme] makes the configuration the only source of truth.

css
:root { --status-page-max-width: 72rem; }[data-theme="slate"] { --status-page-max-width: 64rem; }[data-theme="fern"]  { --status-page-max-width: 64rem; --radius-lg: 0.75rem; }

Status colours

Status colours are the heyo-ui semantic tokens, not a second palette:

TokenMaps to
--color-status-up--color-heyo-success
--color-status-degraded--color-heyo-warning
--color-status-down--color-heyo-danger
--color-status-maintenance--color-heyo-info

One of them changing — for contrast, for a brand — must not leave a status page showing two different greens for the same idea.

Overriding styles

Every layout renders through the same shell, which publishes stable data-slot hooks:

AttributeElement
[data-slot="status-page"]Page container, also data-theme
[data-slot="status-header"]Header
[data-slot="status-logo"]Brand logo
[data-slot="status-overall"]Overall status card or banner
[data-slot="status-monitor-group"]A group disclosure
[data-slot="status-monitor"]A single monitor
[data-slot="status-footer"]Footer

Add your own stylesheet after the bundled one — generated projects already create src/styles/status.css for exactly this:

src/styles/status.css
[data-slot="status-page"] {  --status-page-max-width: 56rem;}[data-theme="onyx"] [data-slot="status-header"] {  border-bottom: 1px solid var(--color-border);}[data-slot="status-monitor"]:hover {  background: color-mix(in oklab, var(--color-foreground) 4%, transparent);}

Target a slot, not a Tailwind class: classes are implementation detail and change between releases, while the slots are part of the contract and are asserted in the package's tests for every registered theme.

Previewing

In a clone of the repository:

bash
bun run theme:preview            # every themebun run theme:preview slate fern # a subsetbun run theme:preview --dark

It renders each registered theme to .heyo-playground/themes/<name>.html from one fabricated snapshot with fixed dates, seeded history and a monitor in every state, using the published stylesheet. Two runs are byte-identical, so a diff in the output is a diff in the theme.

Switching themes

Change one line:

diff
- theme: "slate",+ theme: "onyx",

No stylesheet change, no component change. If you pass theme to <StatusPage /> from the configuration — as every template does — the page follows automatically.

Themes may not fork behaviour

A theme chooses composition: lead with a banner or a card, group monitors into rows or cards, put incidents above or below services. Data loading, colour mode and the subscribe dialog belong to the shell, which is what keeps five themes from becoming five slightly different products.

Related

  • Identity and appearance
  • UI primitives
  • Colour mode
StatusPage component< PreviousUI primitivesNext >

Powered by heyo

On this page

The layoutsOne stylesheetStatus coloursOverriding stylesPreviewingSwitching themes