How to Design a Timeline Section for a Website: Vertical, Horizontal, and Responsive Patterns

by | Oct 15, 2026 | Uncategorized | 0 comments

Almost every company site eventually needs one: a history section, a process walkthrough, or a public roadmap. And almost every one of them breaks on a 375px screen. Good website timeline design is less about decorative connectors and more about choosing the right layout direction, placing date labels where the eye expects them, and writing markup that a screen reader can actually narrate.

This guide is the build sheet we use at FatCow Web Design. You get the decision rules first, then copy-paste CSS Grid patterns for vertical, alternating and horizontal timelines, then an accessibility checklist you can run before launch. The team at shorthand.com reached a similar conclusion.

Three jobs a timeline section can do (pick one)

Before touching CSS, name the job. The job determines the layout, the density, and whether dates even belong in the design.

  • History timeline: “founded in 2016, opened a second office in 2021”. Chronological, past tense, dates are the anchor. Usually 5 to 12 entries.
  • Process timeline: “discovery, wireframes, build, launch”. Ordered but dateless. Numbers or step labels replace years. Usually 3 to 6 entries.
  • Roadmap timeline: “shipped, in progress, planned”. Needs status, not just order. Dates are often coarse (quarters, halves) and sometimes deliberately vague.

Mixing the three in one component is the most common mistake we see. A roadmap needs status chips; a company history does not. Build the variant you need, not the generic one.

timeline web design

Choose the layout direction before you write CSS

The single biggest decision in website timeline design is direction. Here is how the four workable patterns compare.

Pattern Best for Item count Watch out for
Vertical, single column Mobile default, long histories, text-heavy entries Any Page length; add a sticky year marker if over 10 items
Vertical alternating (zigzag) Company history on desktop, short entries with icons 4 to 10 Reading order zigzags; never alternate below 48rem
Horizontal scroll Roadmaps, decade-by-decade stories with images 5 to 20 Discoverability, keyboard access, WCAG reflow
Horizontal stepper 3 to 5 step processes, no scrolling 3 to 5 Text truncation; collapses to vertical early

When to switch from horizontal to vertical

Use content-based rules, not device names:

  1. Under 48rem of available inline space, go vertical single column. Always. No exceptions for alternating layouts.
  2. If each entry needs more than about 25 words, stay vertical even on wide screens. Horizontal cards force truncation and truncation kills the story.
  3. If a card is narrower than 15rem, you have too many horizontal steps. Drop to a scrolling track or go vertical.
  4. If the section sits inside a narrow column or sidebar, use a container query, not a viewport media query. The component should react to its own box.

Markup first: semantics that survive a screen reader

A timeline is an ordered list of events. Say that in HTML and most accessibility work is already done.

<section class="timeline-wrap" aria-labelledby="story-title">
  <h2 id="story-title">Our story</h2>

  <ol class="timeline timeline--alt">
    <li class="timeline__item">
      <div class="timeline__card">
        <time class="timeline__date" datetime="2019-04">April 2019</time>
        <h3 class="timeline__heading">The studio opens</h3>
        <p>Two designers, one rented desk, and a first client who found us on a forum.</p>
      </div>
    </li>

    <li class="timeline__item">
      <div class="timeline__card">
        <time class="timeline__date" datetime="2022-09">September 2022</time>
        <h3 class="timeline__heading">First ecommerce team</h3>
        <p>We hired three developers and shipped 40 stores in twelve months.</p>
      </div>
    </li>
  </ol>
</section>

Why this shape works:

  • <ol> announces “list, 8 items” and gives each entry a position. Order is meaningful, so it is an ordered list, not a <ul>.
  • <time datetime> gives machines a parseable date while the visible label stays human (“Spring 2019”, “Q2”).
  • One wrapper per entry (.timeline__card) lets the list itself own the rail and the item own the dot, which is what makes the Grid version below so short.
  • Headings stay in order. If the section is an h2, entries are h3. Do not jump to h4 because it looks smaller.

What not to do: never put the date inside content: on a pseudo-element. Some screen readers announce generated content, others ignore it, and either way you have lost your datetime value.

timeline web design

Pattern 1: the vertical timeline with CSS Grid and pseudo-elements

This is the mobile baseline and the safest desktop choice for long company histories. The dot is a ::before placed in a narrow grid column, the connector is an absolutely positioned ::after that stops at the last item.

.timeline{
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  row-gap: 2.5rem;
}

.timeline__item{
  position: relative;
  display: grid;
  grid-template-columns: 1rem 1fr;
  column-gap: 1.25rem;
}

/* the dot */
.timeline__item::before{
  content: "";
  grid-column: 1;
  align-self: start;
  inline-size: 1rem;
  block-size: 1rem;
  margin-block-start: 0.35em;
  border-radius: 50%;
  background: #e4572e;
  box-shadow: 0 0 0 4px #fff;
  z-index: 1;
}

/* the connector */
.timeline__item::after{
  content: "";
  position: absolute;
  inset-block: 1.6em -2.5rem;
  inset-inline-start: 0.4375rem;
  inline-size: 2px;
  background: #dcdcdc;
}

.timeline__item:last-child::after{ content: none; }

.timeline__date{
  display: block;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: #6b6b6b;
  letter-spacing: 0.02em;
}

.timeline__heading{ margin: 0.25rem 0 0.5rem; text-wrap: balance; }

Two details that make it feel finished: tabular-nums keeps years optically aligned, and the white box-shadow ring on the dot punches a clean hole in the connector line so the two never touch.

Pattern 2: the alternating desktop layout using subgrid

The zigzag layout is popular for company history sections, and subgrid finally makes it honest: each list item spans the full track set, then its card snaps to the left or right column.

.timeline-wrap{ container-type: inline-size; }

@container (min-width: 48rem){
  .timeline--alt{
    grid-template-columns: 1fr 2px 1fr;
    column-gap: 2.5rem;
    /* the rail, drawn once instead of per item */
    background: linear-gradient(#dcdcdc, #dcdcdc) center / 2px 100% no-repeat;
  }

  .timeline--alt .timeline__item{
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
  }

  .timeline--alt .timeline__item::after{ content: none; }

  .timeline--alt .timeline__item::before{
    grid-column: 2;
    justify-self: center;
  }

  .timeline--alt .timeline__card{ grid-column: 1; text-align: right; }

  .timeline--alt .timeline__item:nth-child(even) .timeline__card{
    grid-column: 3;
    text-align: start;
  }
}

Notes from production use:

  • Drawing the rail as a gradient on the list avoids a stray pseudo-element fighting with auto-placement, and it disappears automatically when the container query stops matching.
  • Right aligned text is fine for two or three lines. Past that, keep both sides left aligned and let the dot do the alternating.
  • Under 48rem everything falls back to Pattern 1 with zero extra code, because the base styles were written mobile first.

Pattern 3: the horizontal scrolling timeline

Horizontal works when entries are short, visual and roughly equal in weight. It is a roadmap pattern more than a history pattern.

<div class="timeline-scroller" role="region" aria-label="Product roadmap" tabindex="0">
  <ol class="timeline timeline--h"> ... </ol>
</div>
.timeline-scroller{
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding-inline: 1rem;
  padding-block-end: 1rem;
}

@container (min-width: 48rem){
  .timeline--h{
    grid-auto-flow: column;
    grid-auto-columns: minmax(15rem, 20rem);
    column-gap: 1.5rem;
    row-gap: 0;
    padding-block-start: 1.75rem;
    background: linear-gradient(#dcdcdc, #dcdcdc) left 0.5rem / 100% 2px no-repeat;
  }

  .timeline--h .timeline__item{
    grid-template-columns: 1fr;
    scroll-snap-align: start;
  }

  .timeline--h .timeline__item::after{ content: none; }
  .timeline--h .timeline__item::before{ margin-block-start: -1.25rem; }
}

Three rules that keep a horizontal timeline usable:

  1. Make the scroll container focusable. tabindex="0" plus role="region" and a label means keyboard users can arrow through it. Browsers have improved here, but the explicit attribute is still the safe choice.
  2. Show that there is more. Let the next card peek by 20 to 40 percent at the right edge, or add a gradient mask. A perfectly flush edge reads as “the end”.
  3. Never nest horizontal scroll inside horizontal scroll, and never let the whole page scroll sideways. WCAG 1.4.10 (Reflow) expects content to work without two dimensional scrolling at 320px.
timeline web design

Date label placement: small decision, big readability gain

Where the date sits changes how fast people scan the section. This is the part most website timeline design tutorials skip. It is argued more carefully on elfsight.com.

Placement Effect Use when
Above the heading, inside the card Safest, reflows perfectly, one reading order Default for mobile and most histories
Dedicated left column (a third grid track) Years align into a scannable ladder Long histories, 10+ entries, desktop
On the opposite side of the rail (mirrored) Looks editorial, but doubles the eye path Short labels only, 4 to 8 entries
On the dot itself Compact, but breaks with long dates Year only, never full dates

Formatting rules we apply every time:

  • Use the coarsest date that is still true. “2024” beats “14 March 2024” for a history section.
  • Keep the format identical down the whole list. One “Q3 2025” among ten “2025” labels looks like a bug.
  • For roadmaps, pair the date with a status word (Shipped, In progress, Planned) and never rely on colour alone to carry it.
  • Ranges use the datetime of the start date and a visible label like “2021 to 2023”.

Accessibility checklist for a timeline component

  • Ordered list markup so position and count are announced.
  • Sequential headings (h2 for the section, h3 per entry) so the whole story appears in the heading outline.
  • Real text for dates in a <time> element, never generated content.
  • Decorative dots and rails built with pseudo-elements or CSS backgrounds, which assistive tech ignores by default. No aria-hidden needed.
  • Contrast: connector lines are decorative, but date labels are text and need 4.5:1 against the background. Grey #999 on white fails.
  • Visible focus on any link or button inside a card, with enough offset that the ring is not clipped by overflow: hidden.
  • Reduced motion: wrap reveal animations in @media (prefers-reduced-motion: no-preference).
  • Zoom test: 320px viewport width and 200 percent text zoom, no clipped dates, no horizontal page scroll.

Scroll-driven reveals, the cheap way

You do not need an animation library or an IntersectionObserver for a fade-up on scroll. CSS scroll-driven animations handle it natively and degrade to “always visible” where unsupported, which is exactly the failure mode you want.

@media (prefers-reduced-motion: no-preference){
  @supports (animation-timeline: view()){
    .timeline__card{
      animation: tl-rise linear both;
      animation-timeline: view();
      animation-range: entry 10% cover 32%;
    }
  }
}

@keyframes tl-rise{
  from{ opacity: 0; translate: 0 1.25rem; }
  to{ opacity: 1; translate: 0 0; }
}

Keep the distance small. A timeline that throws every card 80px across the screen feels slow on a long history section.

Content rules that make the section worth reading

Layout is half the work. The other half is editorial, and it is where most timelines lose people. canva.com goes into the numbers.

  1. Cap it at 8 to 12 entries. If a company has 30 years of history, group by era and let each entry cover a phase.
  2. One idea per entry, 15 to 35 words. Long paragraphs belong on a separate page that the entry links to.
  3. Lead with the outcome, not the announcement. “Opened the Lisbon studio” beats “We are excited to announce”.
  4. Include at least two numbers across the whole timeline. Specifics are what make a history feel real.
  5. End with the present or the next step. A timeline that stops three years ago signals a neglected site.
  6. Do not date a roadmap more precisely than you can deliver. Quarters are a promise; exact dates are a liability.
timeline web design

Pre-launch QA checklist

  1. Test at 320px, 768px and 1440px, plus one narrow container (sidebar or modal) if the component is reusable.
  2. Tab through the section: every interactive element reachable, focus ring visible, scroll container focusable if horizontal.
  3. Run a screen reader over it and confirm it announces a list with the right item count and readable dates.
  4. Swap in the longest real entry you have, not lorem ipsum, and check for overflow.
  5. Check the last item: no orphaned connector line hanging below it.
  6. Disable JavaScript. The timeline should still render fully.
  7. Turn on reduced motion in the OS and confirm all cards are visible without animation.
  8. Confirm images inside cards have explicit width and height plus loading="lazy" below the fold, so the section does not shift layout.

Common mistakes in website timeline design

  • Alternating layout on mobile. It creates a ragged, half-width column and a confusing reading order. Collapse it.
  • Fixed pixel heights on cards. One long entry and the text escapes the box. Let Grid size the rows.
  • Absolutely positioning every dot. A grid column plus a pseudo-element is fewer lines and survives content changes.
  • Carousel-only roadmaps where content is hidden behind arrows and never indexed or read in order.
  • Divs and spans all the way down. Without a list and headings, the section is invisible to assistive tech and to the outline crawlers use to understand structure.
  • Pointless scroll hijacking, where vertical wheel input drives horizontal movement. It breaks expectations and trackpad momentum.

FAQ

Should a website timeline be vertical or horizontal?

Vertical by default. It matches natural page scrolling, handles any number of entries, and reflows on mobile without extra code. Choose horizontal only for short, visual, roughly equal entries such as a product roadmap, and always provide a vertical fallback below 48rem.

What is the best HTML for a timeline section?

A <section> with a heading, an <ol> for the entries, a <time datetime="..."> for each date and an <h3> for each entry title. Everything visual (dots, rails, connectors) should come from CSS pseudo-elements or backgrounds so assistive tech ignores it.

Do I need JavaScript to build a timeline?

No. CSS Grid, subgrid, container queries and scroll-driven animations cover layout, responsiveness and reveal effects. Add JavaScript only for filtering, expanding entries, or loading data from a CMS.

How many items should a company history timeline have?

Between 6 and 12. Fewer than 5 rarely justifies the component, and more than 12 turns into a wall that nobody finishes. Group minor events into a single phase entry instead of listing them all.

Can a timeline help SEO?

Indirectly. A well structured timeline adds crawlable, topically rich text about your company, uses a clean heading hierarchy, and often earns internal links to case studies or service pages. Content locked inside a JavaScript-only carousel loses that benefit, so render the markup server side.

How do I make a horizontal timeline keyboard accessible?

Give the scroll container role="region", an aria-label and tabindex="0" so it can receive focus and respond to arrow keys. Ensure every card is reachable in DOM order and that focused items are scrolled into view rather than clipped.

Need this built properly?

A timeline section looks trivial until the client sends a 40 word entry, a 1998 date and a request for it to work in a sidebar. Our team builds accessible, container-query-ready components that hold up to real content. Get in touch with FatCow Web Design and we will spec the right timeline pattern for your site.

Search Keywords

Recent Posts

Subscribe Now!