Incident update timeline
A vertical incident timeline with colour-coded status dots and timestamps, newest update first, built from a semantic ordered list.
Tailwind CSSFeedback and empty statestimelineincidentstatuslist
Live preview
Code
<section class="mx-auto max-w-xl px-4" aria-labelledby="inc-title">
<h2 id="inc-title" class="text-lg font-semibold text-slate-900">Elevated API errors</h2>
<p class="mb-5 text-sm text-slate-500">Started 14:02 UTC · Resolved after 47 minutes</p>
<!-- Newest update first, as readers expect on a status page -->
<ol class="relative ml-3 border-l-2 border-slate-200">
<li class="mb-6 ml-6">
<span class="absolute -left-[9px] mt-1 size-4 rounded-full border-2 border-white bg-emerald-500" aria-hidden="true"></span>
<div class="flex flex-wrap items-baseline gap-x-2">
<strong class="text-emerald-700">Resolved</strong>
<time datetime="2026-01-12T14:49:00Z" class="text-xs text-slate-500">14:49 UTC</time>
</div>
<p class="mt-1 text-sm text-slate-700">The fix is deployed and error rates are back to normal.</p>
</li>
<li class="mb-6 ml-6">
<span class="absolute -left-[9px] mt-1 size-4 rounded-full border-2 border-white bg-sky-500" aria-hidden="true"></span>
<div class="flex flex-wrap items-baseline gap-x-2">
<strong class="text-sky-700">Monitoring</strong>
<time datetime="2026-01-12T14:31:00Z" class="text-xs text-slate-500">14:31 UTC</time>
</div>
<p class="mt-1 text-sm text-slate-700">A fix was released. We are watching the results.</p>
</li>
<li class="mb-6 ml-6">
<span class="absolute -left-[9px] mt-1 size-4 rounded-full border-2 border-white bg-amber-500" aria-hidden="true"></span>
<div class="flex flex-wrap items-baseline gap-x-2">
<strong class="text-amber-700">Identified</strong>
<time datetime="2026-01-12T14:15:00Z" class="text-xs text-slate-500">14:15 UTC</time>
</div>
<p class="mt-1 text-sm text-slate-700">A database connection limit was reached.</p>
</li>
<li class="ml-6">
<span class="absolute -left-[9px] mt-1 size-4 rounded-full border-2 border-white bg-rose-500" aria-hidden="true"></span>
<div class="flex flex-wrap items-baseline gap-x-2">
<strong class="text-rose-700">Investigating</strong>
<time datetime="2026-01-12T14:02:00Z" class="text-xs text-slate-500">14:02 UTC</time>
</div>
<p class="mt-1 text-sm text-slate-700">Some requests to the API are failing. We are looking into it.</p>
</li>
</ol>
</section>
How it works
What it solves
During an outage people want the current status and the story so far, without hunting through chat messages. A timeline with the latest update on top gives both in one scroll.
How it works
The list is an ol with a left border that acts as the spine. Every item is shifted right with ml-6, and its dot is an absolutely positioned span placed with -left-[9px] so it sits centered on the border line (half of the dot width plus half of the 2px stroke). The white ring around each dot, made with border-white, cuts a clean gap in the spine.
Each update uses a strong word for the phase and a time element with a machine readable datetime attribute, so scripts and assistive tools can parse the time while people read "14:49 UTC". Colours follow a simple lifecycle: rose while investigating, amber once identified, sky when monitoring and green on resolution.
Adapting it
- Render the items from an updates table ordered by newest first.
- Convert times to the reader's zone on the client by reading the
datetimevalue. - Add a short link to the affected components under the heading.
Pitfalls
- Ordered lists announce position numbers to some screen readers; this is fine, but keep the order consistent.
- If you change the dot size, recompute the negative offset.
- Do not drop the text phase and rely on colour; many readers cannot tell the dots apart.
How to use it
- Place the section on your incident detail page.
- Loop updates from your database into the list items, newest first.
- Pick the dot colour and heading colour from the update phase.
- Output the timestamp in the
datetimeattribute in UTC ISO format.
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.