Bootstrap Timeline: Vertical, Horizontal and Responsive
Bootstrap doesn’t have a timeline component, but you can build one from its utilities in a few lines: a vertical line from a border, dots placed with position classes, and cards or plain text for each event. This guide shows four Bootstrap 5.3 timelines, a simple vertical timeline, a timeline with icons and cards, a centered timeline that alternates left and right, and a horizontal timeline for steps or milestones, plus how to make them responsive and accessible.
A simple vertical timeline
A list with a left border for the line, and a dot on each item placed with position-absolute:
<ol class="list-unstyled border-start border-2 ms-2 ps-4">
<li class="position-relative mb-4">
<span class="position-absolute top-0 start-0 translate-middle-x bg-primary border border-4 border-body rounded-circle p-2"
style="margin-left: calc(-1.5rem - 1px); margin-top: .25rem;"></span>
<time class="small text-body-secondary" datetime="2026-11">November 2026</time>
<h3 class="h6 mt-1 mb-1">Version 2.0 released</h3>
<p class="mb-0">A new editor, dark mode, and faster exports.</p>
</li>
<li class="position-relative mb-4">
<span class="position-absolute top-0 start-0 translate-middle-x bg-secondary border border-4 border-body rounded-circle p-2"
style="margin-left: calc(-1.5rem - 1px); margin-top: .25rem;"></span>
<time class="small text-body-secondary" datetime="2026-06">June 2026</time>
<h3 class="h6 mt-1 mb-1">Public beta</h3>
<p class="mb-0">Opened to everyone on the waiting list.</p>
</li>
<li class="position-relative">
<span class="position-absolute top-0 start-0 translate-middle-x bg-secondary border border-4 border-body rounded-circle p-2"
style="margin-left: calc(-1.5rem - 1px); margin-top: .25rem;"></span>
<time class="small text-body-secondary" datetime="2026-01">January 2026</time>
<h3 class="h6 mt-1 mb-1">Project started</h3>
<p class="mb-0">The first prototype was built in a weekend.</p>
</li>
</ol>
How it works:
border-start border-2on the list draws the line, andps-4(1.5rem) moves the content away from it.- Each dot is moved back by the same 1.5rem plus the 1px half of the line, and
translate-middle-xcenters it on the line. border-4 border-bodygives the dot a ring in the page’s background color, so it looks cut out of the line in light and dark mode.<ol>and<time>give the events an order and a machine-readable date.
The inline styles get repetitive, so for more than a few items move them into a small class:
.timeline {
--timeline-gap: 1.5rem;
list-style: none;
margin: 0 0 0 .5rem;
padding-left: var(--timeline-gap);
border-left: 2px solid var(--bs-border-color);
}
.timeline-item {
position: relative;
padding-bottom: 1.5rem;
}
.timeline-item:last-child {
padding-bottom: 0;
}
.timeline-item::before {
content: "";
position: absolute;
top: .3rem;
left: calc(-1 * var(--timeline-gap) - 1px);
width: 1rem;
height: 1rem;
transform: translateX(-50%);
border: 3px solid var(--bs-body-bg);
border-radius: 50%;
background: var(--bs-secondary-color);
}
.timeline-item.is-active::before {
background: var(--bs-primary);
}
<ol class="timeline">
<li class="timeline-item is-active">
<time class="small text-body-secondary" datetime="2026-11-12">Nov 12</time>
<p class="mb-0 fw-semibold">Order shipped</p>
</li>
<li class="timeline-item">
<time class="small text-body-secondary" datetime="2026-11-10">Nov 10</time>
<p class="mb-0">Payment received</p>
</li>
</ol>
The CSS uses Bootstrap’s own variables (--bs-border-color, --bs-body-bg, --bs-primary), so it follows your theme colors and dark mode.
Timeline with icons and cards
For an activity feed, replace the dots with Bootstrap Icons in circles, and put each event in a card:
<ol class="list-unstyled position-relative ms-3">
<li class="d-flex gap-3 pb-4 position-relative">
<span class="position-absolute top-0 bottom-0 border-start border-2" style="left: 1.25rem;"></span>
<span class="flex-shrink-0 d-flex align-items-center justify-content-center rounded-circle text-bg-success position-relative"
style="width: 2.5rem; height: 2.5rem;">
<i class="bi bi-check-lg" aria-hidden="true"></i>
</span>
<div class="card flex-grow-1">
<div class="card-body py-2">
<div class="d-flex justify-content-between">
<strong>Deploy succeeded</strong>
<time class="small text-body-secondary" datetime="2026-11-12T09:41">9:41</time>
</div>
<p class="mb-0 small">main@4f2a9c deployed to production.</p>
</div>
</div>
</li>
<li class="d-flex gap-3 position-relative">
<span class="flex-shrink-0 d-flex align-items-center justify-content-center rounded-circle text-bg-primary position-relative"
style="width: 2.5rem; height: 2.5rem;">
<i class="bi bi-chat-left-text" aria-hidden="true"></i>
</span>
<div class="card flex-grow-1">
<div class="card-body py-2">
<div class="d-flex justify-content-between">
<strong>New comment</strong>
<time class="small text-body-secondary" datetime="2026-11-12T09:12">9:12</time>
</div>
<p class="mb-0 small">Sam: "Looks good, ship it."</p>
</div>
</div>
</li>
</ol>
The line is an absolutely positioned border behind the icons, centered under the 2.5rem circle at left: 1.25rem. The last item has no line, so the timeline ends at its icon. flex-shrink-0 stops the icon from shrinking when the card text is long. See the cards guide for more card layouts.
A centered, alternating timeline
The classic company-history layout has a line down the middle and events alternating left and right. Use the grid, with the line drawn by CSS and the layout stacking on phones:
.timeline-center {
position: relative;
}
.timeline-center::before {
content: "";
position: absolute;
top: 0;
bottom: 0;
left: 1rem;
border-left: 2px solid var(--bs-border-color);
}
.timeline-center .dot {
position: absolute;
left: 1rem;
top: 1.25rem;
width: 1rem;
height: 1rem;
transform: translateX(-50%);
border-radius: 50%;
background: var(--bs-primary);
border: 3px solid var(--bs-body-bg);
}
@media (min-width: 768px) {
.timeline-center::before,
.timeline-center .dot {
left: 50%;
}
}
<div class="timeline-center">
<div class="row g-0 position-relative mb-4">
<span class="dot"></span>
<div class="col-md-6 ps-5 ps-md-3 pe-md-5 text-md-end">
<div class="card card-body">
<h3 class="h6">2024: Founded</h3>
<p class="mb-0 small">Two people and a spare bedroom.</p>
</div>
</div>
</div>
<div class="row g-0 position-relative mb-4">
<span class="dot"></span>
<div class="col-md-6 offset-md-6 ps-5">
<div class="card card-body">
<h3 class="h6">2025: First 1,000 customers</h3>
<p class="mb-0 small">Mostly agencies and freelancers.</p>
</div>
</div>
</div>
<div class="row g-0 position-relative">
<span class="dot"></span>
<div class="col-md-6 ps-5 ps-md-3 pe-md-5 text-md-end">
<div class="card card-body">
<h3 class="h6">2026: Version 2.0</h3>
<p class="mb-0 small">Rebuilt from the ground up.</p>
</div>
</div>
</div>
</div>
g-0removes the row’s negative gutter margins, so the dots line up with the line drawn on the outer container.- On phones, the line sits on the left and every card is full width with
ps-5to clear it. - From
mdup, the line moves to the middle. Odd items take the left half withtext-md-end, and even items take the right half withoffset-md-6. - The grid guide explains
col-md-6andoffset-md-6.
A horizontal timeline
For steps, milestones, or an order tracker, lay the events out in a row with flexbox. The line is the top border of each step:
<ol class="list-unstyled d-flex flex-column flex-md-row gap-3 gap-md-0">
<li class="flex-fill border-top border-3 border-success pt-3 pe-md-3">
<span class="badge rounded-pill text-bg-success mb-2">Done</span>
<h3 class="h6 mb-1">Ordered</h3>
<p class="small text-body-secondary mb-0">Nov 10</p>
</li>
<li class="flex-fill border-top border-3 border-success pt-3 pe-md-3">
<span class="badge rounded-pill text-bg-success mb-2">Done</span>
<h3 class="h6 mb-1">Shipped</h3>
<p class="small text-body-secondary mb-0">Nov 12</p>
</li>
<li class="flex-fill border-top border-3 pt-3 pe-md-3" aria-current="step">
<span class="badge rounded-pill text-bg-primary mb-2">In transit</span>
<h3 class="h6 mb-1">Out for delivery</h3>
<p class="small text-body-secondary mb-0">Expected Nov 14</p>
</li>
<li class="flex-fill border-top border-3 pt-3">
<span class="badge rounded-pill text-bg-secondary mb-2">Next</span>
<h3 class="h6 mb-1">Delivered</h3>
</li>
</ol>
flex-column flex-md-row stacks the steps on phones and puts them in a row from 768px up. Completed steps get a green line, and aria-current="step" marks the current one for screen readers. For a progress bar version, see the progress bar guide.
For many events that don’t fit on one screen, make the row scroll sideways instead of stacking: d-flex overflow-x-auto with a fixed width on each item, such as style="min-width: 14rem;".
Accessibility
- Use an ordered list (
<ol>), so screen readers announce the number of events and their order. - Put dates in
<time>elements with adatetimeattribute. - Dots and lines are decoration. If they carry meaning, such as a green dot for done, also say it in text, as the badges above do.
- Give each event a heading if the timeline is a main part of the page, so people can jump between events.
- Check that the line and dot colors have enough contrast with the background.
FAQ
Does Bootstrap have a timeline component?
No. Bootstrap 5 has no timeline component, but you can build one with its utilities: a border-start line on a list, dots positioned with position-absolute and translate-middle-x, and cards or text for each event. A small CSS class makes it easier to reuse.
How do I make a vertical timeline in Bootstrap 5?
Use an <ol class="list-unstyled border-start border-2 ms-2 ps-4"> for the line, and give each <li> the class position-relative with an absolutely positioned dot moved back onto the line. Add the date in a <time> element and the event text below it.
How do I make a horizontal timeline in Bootstrap?
Put the events in a flex row, d-flex flex-column flex-md-row, with flex-fill and a top border on each item for the line. It stacks on phones and becomes a row from the md breakpoint. For many events, use overflow-x-auto to scroll sideways.
How do I make a responsive timeline that alternates left and right?
Use grid rows with col-md-6 for left items and col-md-6 offset-md-6 for right items, and a CSS line that sits on the left on phones and moves to left: 50% from 768px up. On phones every item stacks on one side of the line.
Do I need JavaScript for a Bootstrap timeline?
No. Every timeline in this guide is HTML and CSS only. You’d only add JavaScript to load events dynamically or to animate items as they scroll into view.
Try it in the builder
Make these changes visually with a live preview, then export clean Bootstrap Sass or CSS.
Open the Builder