Open demo

CSS code

HTML
<ol class="thread">
  <li class="item"><span class="av" style="background:#6366f1" aria-hidden="true">RM</span>
    <div class="msg"><div class="who"><b>Rosa M.</b><span class="when">opened this · <time datetime="2026-09-12T10:20">3 days ago</time></span></div>
      <p>The horizontal timeline overflows on iOS Safari below 380px. Everything else is fine — it
        looks like the connector is being measured before the font loads.</p></div></li>

  <li class="sys"><b>Aigars K.</b> added the label <b>bug</b> · <time datetime="2026-09-12T11:05">3 days ago</time></li>

  <li class="item"><span class="av" style="background:#0ea5e9" aria-hidden="true">AK</span>
    <div class="msg"><div class="who"><b>Aigars K.</b><span class="when"><time datetime="2026-09-13T09:40">2 days ago</time></span></div>
      <p>Reproduced. It is the flex container sizing to <code>max-content</code> — the same trap we
        hit on the SSO card. Fix is <code>minmax(0,1fr)</code> on the track.</p></div>
    <ol class="replies"><li><div class="msg"><div class="who"><b>Rosa M.</b><span class="when"><time datetime="2026-09-13T12:15">2 days ago</time></span></div>
      <p>That did it. Want me to check the other four horizontal sets for the same thing?</p></div></li></ol></li>

  <li class="sys"><b>Tomas P.</b> referenced this in commit <b>a41c9f2</b> · <time datetime="2026-09-14T16:30">yesterday</time></li>

  <li class="item"><span class="av" style="background:#16a34a" aria-hidden="true">TP</span>
    <div class="msg"><div class="who"><b>Tomas P.</b><span class="when">closed this · <time datetime="2026-09-14T17:02">yesterday</time></span></div>
      <p>Fixed across all six horizontal designs and added a 380px check to the build script.</p></div></li>
</ol>
CSS
/* Discussion thread: one <ol> holding comments and lighter system events on a shared spine.
   Replies nest as their own <ol>. Avatars are decorative (the name follows), so they are aria-hidden. */
.thread{--th-bg:#f5f7fb;--th-line:#e3e8f2;--th-text:#4a5570;--th-light:#646f8b;--th-sysname:#5b6683;
  width:100%;max-width:600px;position:relative;margin:0;padding:0 0 0 46px;list-style:none}
.thread,.thread *{box-sizing:border-box}
.thread :where(ol,li,p){margin:0;padding:0;list-style:none}
.thread::before{content:"";position:absolute;left:17px;top:14px;bottom:14px;width:2px;background:var(--th-line)}
.thread .item{position:relative;margin-bottom:20px}
.thread .item:last-child{margin-bottom:0}
.thread .av{position:absolute;left:-46px;top:0;width:34px;height:34px;border-radius:50%;display:grid;
  place-items:center;color:#fff;font-size:.74rem;font-weight:800;border:3px solid var(--th-bg)}
.thread .msg{background:#fff;border:1px solid var(--th-line);border-radius:12px;padding:13px 15px}
.thread .who{display:flex;align-items:baseline;gap:8px;margin-bottom:6px;flex-wrap:wrap}
.thread .who b{font-size:.87rem}
.thread .who .when{font-size:.74rem;color:var(--th-light)}
.thread .msg p{font-size:.85rem;color:var(--th-text);line-height:1.65}
.thread .msg code{background:#f1f4fa;padding:1px 5px;border-radius:4px;font-size:.86em}
.thread .sys{position:relative;font-size:.79rem;color:var(--th-light);padding:5px 0 5px 2px;margin-bottom:20px}
.thread .sys::before{content:"";position:absolute;left:-36px;top:9px;width:12px;height:12px;border-radius:50%;
  background:#e7ebf5;border:3px solid var(--th-bg)}
.thread .sys b{color:var(--th-sysname);font-weight:700}
.thread .replies{margin-left:26px;margin-top:12px}
.thread .replies .msg{background:#fafbfe}

Bootstrap 5 code

Requires: Bootstrap 5.3.8 CSS

HTML
<ol class="thread list-unstyled position-relative w-100 m-0">
  <li class="item position-relative"><span class="av position-absolute top-0 d-grid rounded-circle text-white fw-bolder" style="background:#6366f1" aria-hidden="true">RM</span>
    <div class="msg"><div class="who d-flex flex-wrap align-items-baseline"><b>Rosa M.</b><span class="when">opened this · <time datetime="2026-09-12T10:20">3 days ago</time></span></div>
      <p>The horizontal timeline overflows on iOS Safari below 380px. Everything else is fine — it
        looks like the connector is being measured before the font loads.</p></div></li>

  <li class="sys position-relative"><b>Aigars K.</b> added the label <b>bug</b> · <time datetime="2026-09-12T11:05">3 days ago</time></li>

  <li class="item position-relative"><span class="av position-absolute top-0 d-grid rounded-circle text-white fw-bolder" style="background:#0ea5e9" aria-hidden="true">AK</span>
    <div class="msg"><div class="who d-flex flex-wrap align-items-baseline"><b>Aigars K.</b><span class="when"><time datetime="2026-09-13T09:40">2 days ago</time></span></div>
      <p>Reproduced. It is the flex container sizing to <code>max-content</code> — the same trap we
        hit on the SSO card. Fix is <code>minmax(0,1fr)</code> on the track.</p></div>
    <ol class="replies list-unstyled m-0"><li><div class="msg"><div class="who d-flex flex-wrap align-items-baseline"><b>Rosa M.</b><span class="when"><time datetime="2026-09-13T12:15">2 days ago</time></span></div>
      <p>That did it. Want me to check the other four horizontal sets for the same thing?</p></div></li></ol></li>

  <li class="sys position-relative"><b>Tomas P.</b> referenced this in commit <b>a41c9f2</b> · <time datetime="2026-09-14T16:30">yesterday</time></li>

  <li class="item position-relative"><span class="av position-absolute top-0 d-grid rounded-circle text-white fw-bolder" style="background:#16a34a" aria-hidden="true">TP</span>
    <div class="msg"><div class="who d-flex flex-wrap align-items-baseline"><b>Tomas P.</b><span class="when">closed this · <time datetime="2026-09-14T17:02">yesterday</time></span></div>
      <p>Fixed across all six horizontal designs and added a 380px check to the build script.</p></div></li>
</ol>
CSS
/* Bootstrap list and flex utilities; the spine, avatar placement and message boxes are custom CSS.
   Replies nest as their own <ol>. Avatars are decorative (the name follows), so they are aria-hidden. */
.thread{--th-bg:#f5f7fb;--th-line:#e3e8f2;--th-text:#4a5570;--th-light:#646f8b;--th-sysname:#5b6683;max-width:600px;padding-left:46px}
.thread::before{content:"";position:absolute;left:17px;top:14px;bottom:14px;width:2px;background:var(--th-line)}
.thread .item{margin-bottom:20px}
.thread .item:last-child{margin-bottom:0}
.thread .av{left:-46px;width:34px;height:34px;place-items:center;font-size:.74rem;border:3px solid var(--th-bg)}
.thread .msg{background:#fff;border:1px solid var(--th-line);border-radius:12px;padding:13px 15px}
.thread .who{gap:8px;margin-bottom:6px}
.thread .who b{font-size:.87rem}
.thread .who .when{font-size:.74rem;color:var(--th-light)}
.thread .msg p{font-size:.85rem;color:var(--th-text);line-height:1.65;margin:0}
.thread .msg code{background:#f1f4fa;color:inherit;padding:1px 5px;border-radius:4px;font-size:.86em}
.thread .sys{font-size:.79rem;color:var(--th-light);padding:5px 0 5px 2px;margin-bottom:20px}
.thread .sys::before{content:"";position:absolute;left:-36px;top:9px;width:18px;height:18px;border-radius:50%;
  background:#e7ebf5;border:3px solid var(--th-bg)}
.thread .sys b{color:var(--th-sysname);font-weight:700}
.thread .replies{margin-left:26px!important;margin-top:12px!important}
.thread .replies .msg{background:#fafbfe}

Tailwind 4 code

Requires: Tailwind CSS 4

HTML
<ol class="relative w-full max-w-[600px] pl-[46px] before:absolute before:top-3.5 before:bottom-3.5 before:left-[17px] before:w-0.5 before:bg-th-line">
  <li class="relative mb-5 last:mb-0"><span class="absolute top-0 -left-[46px] grid size-[34px] place-items-center rounded-full border-3 border-th-bg text-[.74rem] font-extrabold text-white" style="background:#6366f1" aria-hidden="true">RM</span>
    <div class="rounded-xl border border-th-line bg-white px-[15px] py-[13px]"><div class="mb-1.5 flex flex-wrap items-baseline gap-2"><b class="text-[.87rem] font-bold">Rosa M.</b><span class="text-[.74rem] text-th-light">opened this · <time datetime="2026-09-12T10:20">3 days ago</time></span></div>
      <p class="text-[.85rem] leading-[1.65] text-th-text">The horizontal timeline overflows on iOS Safari below 380px. Everything else is fine — it
        looks like the connector is being measured before the font loads.</p></div></li>

  <li class="relative mb-5 py-[5px] pr-0 pl-0.5 text-[.79rem] text-th-light before:absolute before:top-[9px] before:-left-9 before:size-[18px] before:rounded-full before:border-3 before:border-th-bg before:bg-[#e7ebf5] [&_b]:font-bold [&_b]:text-th-sysname"><b>Aigars K.</b> added the label <b>bug</b> · <time datetime="2026-09-12T11:05">3 days ago</time></li>

  <li class="relative mb-5 last:mb-0"><span class="absolute top-0 -left-[46px] grid size-[34px] place-items-center rounded-full border-3 border-th-bg text-[.74rem] font-extrabold text-white" style="background:#0ea5e9" aria-hidden="true">AK</span>
    <div class="rounded-xl border border-th-line bg-white px-[15px] py-[13px]"><div class="mb-1.5 flex flex-wrap items-baseline gap-2"><b class="text-[.87rem] font-bold">Aigars K.</b><span class="text-[.74rem] text-th-light"><time datetime="2026-09-13T09:40">2 days ago</time></span></div>
      <p class="text-[.85rem] leading-[1.65] text-th-text">Reproduced. It is the flex container sizing to <code class="rounded bg-[#f1f4fa] px-[5px] py-px text-[.86em]">max-content</code> — the same trap we
        hit on the SSO card. Fix is <code class="rounded bg-[#f1f4fa] px-[5px] py-px text-[.86em]">minmax(0,1fr)</code> on the track.</p></div>
    <ol class="mt-3 ml-[26px]"><li><div class="rounded-xl border border-th-line bg-[#fafbfe] px-[15px] py-[13px]"><div class="mb-1.5 flex flex-wrap items-baseline gap-2"><b class="text-[.87rem] font-bold">Rosa M.</b><span class="text-[.74rem] text-th-light"><time datetime="2026-09-13T12:15">2 days ago</time></span></div>
      <p class="text-[.85rem] leading-[1.65] text-th-text">That did it. Want me to check the other four horizontal sets for the same thing?</p></div></li></ol></li>

  <li class="relative mb-5 py-[5px] pr-0 pl-0.5 text-[.79rem] text-th-light before:absolute before:top-[9px] before:-left-9 before:size-[18px] before:rounded-full before:border-3 before:border-th-bg before:bg-[#e7ebf5] [&_b]:font-bold [&_b]:text-th-sysname"><b>Tomas P.</b> referenced this in commit <b>a41c9f2</b> · <time datetime="2026-09-14T16:30">yesterday</time></li>

  <li class="relative mb-5 last:mb-0"><span class="absolute top-0 -left-[46px] grid size-[34px] place-items-center rounded-full border-3 border-th-bg text-[.74rem] font-extrabold text-white" style="background:#16a34a" aria-hidden="true">TP</span>
    <div class="rounded-xl border border-th-line bg-white px-[15px] py-[13px]"><div class="mb-1.5 flex flex-wrap items-baseline gap-2"><b class="text-[.87rem] font-bold">Tomas P.</b><span class="text-[.74rem] text-th-light">closed this · <time datetime="2026-09-14T17:02">yesterday</time></span></div>
      <p class="text-[.85rem] leading-[1.65] text-th-text">Fixed across all six horizontal designs and added a 380px check to the build script.</p></div></li>
</ol>
CSS
@theme {
  --color-th-bg: #f5f7fb;
  --color-th-line: #e3e8f2;
  --color-th-text: #4a5570;
  --color-th-light: #646f8b;
  --color-th-sysname: #5b6683;
}

About this set

An issue or ticket thread that mixes comments and lighter system events on a single spine, in the style of a code review or support conversation. Comments are white boxes with the author’s initials in a coloured avatar on the spine, a name, a relative time and the message, which can include inline code. A reply nests under its parent comment, indented and on a slightly tinted background. System events, such as a label being added or a commit referencing the issue, are a single line of grey text with a small dot on the spine, so they read as context rather than conversation. Use it for issue trackers, support tickets, approval histories or any record where people and the system both act. The whole thread is one ordered list, with replies as a nested ordered list, and every relative time such as 3 days ago is a time element carrying the exact ISO date and time. The avatars are hidden from screen readers because the author’s name follows immediately. The Bootstrap version uses list and flex utilities with a small custom block, and the Tailwind version is utilities only.

What’s included

  • Comments and system events on one spine
  • Nested reply on a tinted background
  • Initial avatars placed on the spine
  • Relative times backed by ISO datetime values
  • Inline code styling inside messages

Accessibility

The thread is an ordered list in time order, with replies as a nested ordered list, so screen readers convey both sequence and nesting. Avatars are aria-hidden because the author's name follows. Relative times are time elements with exact datetime values. Grey metadata was darkened to meet 4.5:1, and nothing animates.

Customise it

Change --th-bg to your page background (it rings the avatars), and --th-line, --th-text and --th-light on .thread for the spine and text (plain CSS and Bootstrap), or the --color-th-* theme colours in Tailwind. Avatar colours are inline styles.