Status components with uptime bars
A status page component list with a state badge and a 45-day bar strip per service, coloured by daily availability.
Tailwind CSSDashboard widgetsstatus-pageuptimebarsmonitoring
Live preview
Code
<section class="mx-auto max-w-2xl px-4" aria-labelledby="status-title">
<h2 id="status-title" class="mb-4 text-lg font-semibold text-slate-900">System status</h2>
<ul id="components" class="divide-y divide-slate-200 rounded-xl border border-slate-200 bg-white"></ul>
</section>
// Each day is a number: 100 = fully up, lower = partial outage, null = no data.
const components = [
{ name: 'Website', state: 'operational', uptime: 99.98, days: Array.from({ length: 45 }, () => 100) },
{ name: 'API', state: 'degraded', uptime: 99.41, days: Array.from({ length: 45 }, (_, i) => (i === 38 ? 92 : 100)) },
{ name: 'Payments', state: 'outage', uptime: 98.2, days: Array.from({ length: 45 }, (_, i) => (i > 41 ? 40 : 100)) },
];
const badge = {
operational: 'bg-emerald-100 text-emerald-800',
degraded: 'bg-amber-100 text-amber-800',
outage: 'bg-rose-100 text-rose-800',
};
const barColor = (v) => (v === null ? 'bg-slate-200' : v >= 99 ? 'bg-emerald-500' : v >= 90 ? 'bg-amber-400' : 'bg-rose-500');
document.getElementById('components').innerHTML = components.map((c) => `
<li class="p-4">
<div class="mb-2 flex items-center justify-between">
<span class="font-medium text-slate-900">${c.name}</span>
<span class="rounded-full px-2 py-0.5 text-xs font-medium capitalize ${badge[c.state]}">${c.state}</span>
</div>
<div class="flex h-8 gap-px" role="img" aria-label="${c.name} uptime over the last ${c.days.length} days: ${c.uptime}%">
${c.days.map((v, i) => `<span class="flex-1 rounded-sm ${barColor(v)}" title="${c.days.length - i} days ago: ${v ?? 'no data'}%"></span>`).join('')}
</div>
<div class="mt-1 flex justify-between text-xs text-slate-500"><span>${c.days.length} days ago</span><span>${c.uptime}% uptime</span><span>Today</span></div>
</li>`).join('');
How it works
What it solves
Status pages answer two questions: is everything working now, and has it been reliable lately. A badge answers the first, while a row of daily bars answers the second at a glance, the way users expect from a public status site.
How it works
Each component is an object with a current state, an overall uptime figure and an array of daily availability percentages. The script maps every day to a thin flex child; barColor picks green at 99% and above, amber from 90%, rose below that, and grey when the value is null for days without data. The bars sit in a flex-1 row with a one pixel gap, so any number of days fills the same width without a chart library.
The strip is given role="img" with a text summary, since forty-five coloured boxes would be noise for a screen reader. Each bar still carries a title tooltip for pointer users who hover for the exact day.
Adapting it
- Load the array from your own endpoint or render the markup on the server instead of in the browser.
- Adjust the colour thresholds to match the service level you promise.
- Make the period 30 or 90 days just by changing the array length.
Pitfalls
- Compute daily percentages from checks, not from an average of averages.
- Escape component names if they are user supplied before using template strings with
innerHTML. - Never use colour alone; keep the textual badge.
How to use it
- Add the section markup to your status page and load the script after it.
- Replace the sample
componentsarray with data from your monitoring storage. - Keep the state keys in sync with the badge classes in the script, or add more.
- Escape any dynamic names before inserting them.
Licence: DEV3 Snippet Licence. Free to use, change and ship in personal and commercial projects. Attribution is appreciated, not required. Please do not redistribute snippets as a collection.