Uptime Status Page — Service History Bars HTML CSS

Uptime Status Page · Dashboards · Plain HTML, CSS & JS · Live preview

Share & Support

What's included

Features

90-day history bars per service
Each service shows a full quarter of daily status as individual colored bars, generated from data rather than images.
Zero-JS hover tooltips
A CSS ::after pseudo-element reads each bar's data-tip attribute, avoiding a tooltip library for 90+ elements per service.
Self-consistent uptime percentage
The displayed uptime % is computed by counting the same bars shown visually, so the number and the graphic can never disagree.
Aggregated worst-status banner
The overall banner reflects the single worst service status present, with matching color and message severity.
Live-status-consistent history
The most recent history bar always matches the service's actual current status, even though earlier days are randomized.
Three-tier status system
Operational, degraded, and outage each get a distinct color used consistently across the dot, label, bars, and banner.
Compact, scan-friendly layout
Service name, current status, history, and uptime percentage all fit in a few rows per service for fast scanning.
Data-driven service list
Adding, removing, or renaming a service is a one-line change to the SERVICES array — no markup duplication required.

About this UI Snippet

Uptime Status Page — 90-Day History Bars, Hover Tooltips & Aggregated Status

Screenshot of the Uptime Status Page snippet rendered live

A public status page exists to answer one question fast — "is it just me, or is the whole service down?" — and the format every major status page (Statuspage, Better Uptime, Cachet) converges on is the same: a banner summarizing overall health, and a row of tiny colored bars per service showing recent history at a glance. This snippet builds that exact pattern in plain HTML, CSS, and vanilla JavaScript.

History bars as data, not images

Each service renders 90 thin <div> bars in a flex row, one per day, colored green/amber/red for operational/degraded/outage. genHistory() generates a randomized history that's mostly green with rare amber and red days, and the *last* bar always reflects the service's actual current status — so the simulated history stays consistent with the live status shown in the row above it. Replace genHistory() with real incident data and the rendering needs no changes.

Hover tooltips without a tooltip library

Each bar carries its day-relative label and status in a data-tip attribute, and a pure-CSS ::after pseudo-element reads it via content: attr(data-tip) on hover — no JavaScript positioning logic and no extra DOM nodes per bar, which matters here since there are 90 bars × however many services. This is the same zero-JS tooltip technique used for lightweight hint text throughout this library.

Uptime percentage, computed from the bars themselves

uptimePct() doesn't take a separate "99.9% uptime" number from anywhere — it counts how many of the 90 generated bars are operational and divides by the total. This guarantees the displayed percentage and the visual bar row can never contradict each other, which is a real bug class in hand-maintained status pages where the number and the history graphic are updated separately and drift apart.

Aggregated overall status

The top banner doesn't just say "operational" by default — updateOverall() reduces every service's status to find the *worst* one present (outage beats degraded beats operational) and reflects that exact severity in both the banner's color and its message. A single degraded service is enough to turn the whole banner amber; a single outage turns it red — exactly how users expect "is everything okay?" to be answered.

Why a status page exists separately from internal monitoring

Internal dashboards (Grafana, Datadog) are built for engineers diagnosing a problem; a public status page is built for everyone else asking one question fast. Keeping it as its own simple, low-dependency page — rather than exposing the internal monitoring tool directly — also means it can stay up and informative even during an incident that's affecting other parts of the infrastructure, which is exactly the moment a status page matters most.

Build with AI

Build, Understand, Optimize, and Extend It With AI

Instead of working through the aggregation logic by hand, paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly how updateOverall() uses the rank object to reduce five independent service statuses down to a single worst-case banner state, and why uptimePct() recomputes its percentage by counting the same bars array rather than storing a separately maintained number. It's also worth asking about the hover tooltips — have it explain why data-tip plus a CSS ::after avoids creating ninety extra DOM nodes per service, and whether that approach still holds up with many more services or a longer history window. For extending it, have it add a written incident log that links specific degraded/outage days to a description, a way to filter the service list, or an auto-refresh polling loop that re-fetches live status on an interval. Treat the code less like a finished artifact and more like a starting point for a conversation.

Prompt to recreate it

Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:

text
Build a public uptime status page in plain HTML, CSS, and vanilla JavaScript with no libraries.

Requirements:
- A list of services, each with a name and a current status of "operational", "degraded", or "outage".
- For each service, generate a 90-day history of daily statuses, mostly operational with rare degraded/outage days, but force the most recent (today's) entry to always match that service's actual current status so the generated history never contradicts the live status shown above it.
- Render each day of history as its own thin colored bar in a horizontal row (not as an image), colored per its status, with a tooltip that appears on hover showing that day's relative label (e.g. "12d ago") and status — implemented purely with a data attribute and a CSS ::after pseudo-element reading it via content: attr(), with no JavaScript-positioned tooltip element and no extra DOM node per bar.
- Compute each service's displayed uptime percentage by counting how many of its own 90 generated history bars are "operational" and dividing by the total — never from a separate hardcoded number — so the displayed percentage and the visual bar row can never disagree.
- Compute one aggregated overall status banner by reducing every service's status to find the single worst one present (outage ranks worse than degraded, which ranks worse than operational), and reflect that severity in both the banner's color and its message text.
- Make it possible to regenerate the entire page (all bars, percentages, and the banner) from a single function call after editing the underlying service list or statuses.

Step by step

How to Use

  1. 1
    Paste HTML, CSS, and JSA status page renders with an overall banner and five services, each with a row of 90 colored history bars.
  2. 2
    Read the overall bannerIts color and message reflect the single worst status across every service — amber for any degraded service, red for any outage.
  3. 3
    Hover a history barA tooltip shows that day's relative date and status (e.g. "12d ago · Operational") without any extra markup per bar.
  4. 4
    Check the uptime percentageEach service's footer shows a percentage computed directly from its own visible 90-day bar history.
  5. 5
    Edit the servicesChange any entry's name or status in SERVICES, then call buildServices() to regenerate the whole page including the overall banner.
  6. 6
    Connect real incident dataReplace genHistory()'s random generator with your actual per-day status history fetched from an incident/monitoring API.

Real-world uses

Common Use Cases

SaaS and API status pages
The standard public-facing status.yourcompany.com page showing real-time and historical service health.
Internal infrastructure dashboards
Show on-call engineers a quick visual history of which internal services have been flaky recently.
Incident communication pages
Pair with a changelog feed to show both current status and a written incident history.
Multi-region service health
Use each "service" row to represent a region or data center instead of a product feature.
Vendor and dependency monitoring
Track the uptime of third-party APIs and services your product depends on in one consolidated view.
Learning data-driven dashboards
A clear example of deriving every displayed number and color from the same underlying array — compare with a status dashboard for a metric-tile variant.

Got questions?

Frequently Asked Questions

Replace genHistory()'s random-status loop with a fetch to your monitoring or incident-management API, mapping each returned day to 'operational', 'degraded', or 'outage'; keep the same array shape so buildServices() and uptimePct() need no other changes.

For days with a 'degraded' or 'outage' status, attach an incident summary string and render a list of those summaries (with dates) beneath the bar row or in a separate "Past incidents" section, linking each entry back to the relevant day.

Change the DAYS constant — genHistory(), the bar rendering, and uptimePct() all derive their loop length and percentage calculation from that single value.

Wrap a fetch-and-rebuild call in setInterval (e.g. every 60 seconds), updating each service's live status from your API before calling buildServices() again, and update the "Updated just now" label with the current timestamp.

In React, keep services in state and derive history/uptime with useMemo per service, rendering bars with .map(); in Vue, use a computed services array with nested v-for; in Angular, use *ngFor with a pipe for the uptime percentage. The worst-status reduction for the overall banner ports directly into each framework.