Keyboard shortcut: Ctrl + K
Get started

Timeline

VTimeline lists dated events in order. Each VTimelineItem has a marker on the line, a date, a title and content of its own.

Usage

vue
  1. Order shipped

    The parcel left our warehouse in Lyon.
  2. Payment confirmed

    Paid by card ending in 4242.
  3. Order placed

    Three items, delivered to Paris.
<script setup lang="ts">
import { VTimeline, VTimelineItem } from 'vectis-ui'
</script>

<template>
  <VTimeline aria-label="Order history">
    <VTimelineItem datetime="2026-10-06T09:15" title="Order shipped">
      The parcel left our warehouse in Lyon.
    </VTimelineItem>
    <VTimelineItem datetime="2026-10-05T16:40" title="Payment confirmed">
      Paid by card ending in 4242.
    </VTimelineItem>
    <VTimelineItem datetime="2026-10-05T16:32" title="Order placed">
      Three items, delivered to Paris.
    </VTimelineItem>
  </VTimeline>
</template>

Examples

Dates in a column

layout="split" puts the dates in a column across the line, as wide as the longest date up to a third of the width. Below 30rem, the timeline falls back to stacked.

vue
  1. Order shipped

    The parcel left our warehouse in Lyon.
  2. Payment confirmed

    Paid by card ending in 4242.
  3. Order placed

    Three items, delivered to Paris.
<script setup lang="ts">
import { VTimeline, VTimelineItem } from 'vectis-ui'
</script>

<template>
  <VTimeline layout="split" aria-label="Order history">
    <VTimelineItem datetime="2026-10-06T09:15" title="Order shipped">
      The parcel left our warehouse in Lyon.
    </VTimelineItem>
    <VTimelineItem datetime="2026-10-05T16:40" title="Payment confirmed">
      Paid by card ending in 4242.
    </VTimelineItem>
    <VTimelineItem datetime="2026-10-05T16:32" title="Order placed">
      Three items, delivered to Paris.
    </VTimelineItem>
  </VTimeline>
</template>

Alternating sides

layout="alternate" sends every other event across the line, its date facing it, and falls back to stacked below 36rem. A year or a month is written at that precision. Both side-by-side layouts take their width from their parent: in a flex row, give the timeline a basis of its own.

vue
  1. Project started

    A handful of components for an internal tool.
  2. First public preview

    Published on npm with twelve components.
  3. Version 1.0

    A stable API, documented in English and French.
  4. Version 2.0

    Design tokens, dark theme and nineteen new components.
<script setup lang="ts">
import { VTimeline, VTimelineItem } from 'vectis-ui'
</script>

<template>
  <VTimeline layout="alternate" :heading-level="3">
    <VTimelineItem datetime="2019" title="Project started">
      A handful of components for an internal tool.
    </VTimelineItem>
    <VTimelineItem datetime="2021-03" title="First public preview">
      Published on npm with twelve components.
    </VTimelineItem>
    <VTimelineItem datetime="2024-09" title="Version 1.0">
      A stable API, documented in English and French.
    </VTimelineItem>
    <VTimelineItem datetime="2026-10" title="Version 2.0">
      Design tokens, dark theme and nineteen new components.
    </VTimelineItem>
  </VTimeline>
</template>

Horizontal

orientation="horizontal" lays the events across, their markers, dates and titles in line. When they no longer fit, the list scrolls and is a tab stop so that a keyboard can scroll it.

vue
  1. Research

  2. Design

  3. Build

  4. Beta

  5. Launch

<script setup lang="ts">
import { VTimeline, VTimelineItem } from 'vectis-ui'
import { code } from 'vectis-ui/icons'
</script>

<template>
  <VTimeline orientation="horizontal" aria-label="Roadmap">
    <VTimelineItem datetime="2026-01" title="Research" tone="neutral" />
    <VTimelineItem datetime="2026-03" title="Design" tone="neutral" />
    <VTimelineItem datetime="2026-06" title="Build" :icon="code" />
    <VTimelineItem datetime="2026-09" title="Beta" />
    <VTimelineItem datetime="2026-11" title="Launch" />
  </VTimeline>
</template>

Markers

tone paints the marker and icon draws it in a round badge. The marker slot replaces it, with an avatar for instance. Markers are hidden from screen readers: say in the title what the tone means.

vue
  1. Deployed to production

    Release 2.0.1 is live.
  2. Tests retried

    Two browser tests passed on the second attempt.
  3. Build failed

    Type error in the date input.
  4. Camille approved the changes

  5. Commit pushed

<script setup lang="ts">
import { VAvatar, VTimeline, VTimelineItem } from 'vectis-ui'
import { check_circle, code, error } from 'vectis-ui/icons'
</script>

<template>
  <VTimeline aria-label="Deployments">
    <VTimelineItem
      datetime="2026-10-06T10:02"
      title="Deployed to production"
      tone="success"
      :icon="check_circle"
    >
      Release 2.0.1 is live.
    </VTimelineItem>
    <VTimelineItem datetime="2026-10-06T09:48" title="Tests retried" tone="warning">
      Two browser tests passed on the second attempt.
    </VTimelineItem>
    <VTimelineItem datetime="2026-10-06T09:30" title="Build failed" tone="danger" :icon="error">
      Type error in the date input.
    </VTimelineItem>
    <VTimelineItem datetime="2026-10-06T09:20" title="Camille approved the changes">
      <template #marker>
        <VAvatar name="Camille Martin" size="sm" />
      </template>
    </VTimelineItem>
    <VTimelineItem datetime="2026-10-06T09:12" title="Commit pushed" tone="neutral" :icon="code" />
  </VTimeline>
</template>

Dates

timeText shows a relative date while the <time> keeps the exact one. locale and formatOptions change how days and moments are written. On a page rendered on a server, set timeZone in formatOptions for dates that carry an offset.

vue
  1. Camille commented

  2. Sam approved

  3. Alex opened it

  1. Kick-off

  2. Design review

  3. Release

<script setup lang="ts">
import { VTimeline, VTimelineItem } from 'vectis-ui'
</script>

<template>
  <div class="dates">
    <VTimeline size="sm" aria-label="Activity">
      <VTimelineItem datetime="2026-10-06T11:58" time-text="Just now" title="Camille commented" />
      <VTimelineItem datetime="2026-10-06T10:00" time-text="2 hours ago" title="Sam approved" />
      <VTimelineItem datetime="2026-10-05T17:20" time-text="Yesterday" title="Alex opened it" />
    </VTimeline>
    <VTimeline
      size="sm"
      locale="fr-FR"
      :format-options="{ weekday: 'long', day: 'numeric', month: 'long' }"
      aria-label="Planning"
    >
      <VTimelineItem datetime="2026-10-12" title="Kick-off" />
      <VTimelineItem datetime="2026-10-14" title="Design review" />
      <VTimelineItem datetime="2026-10-19" title="Release" />
    </VTimeline>
  </div>
</template>

<style scoped>
.dates {
  display: flex;
  flex-wrap: wrap;
  gap: var(--vectis-space-8);
}

.dates > * {
  flex: 1 1 14rem;
}
</style>

API

Props

VTimeline
PropTypeDefault
orientationTimelineOrientation'vertical' | 'horizontal''vertical'
Whether the events run down the page or across it.
layoutTimelineLayout'stacked' | 'split' | 'alternate''stacked'
Where a vertical timeline puts the dates: above the titles, in a column across the line, or across from content on alternating sides.
sizeTimelineSize'sm' | 'md''md'
Density of the spacing, markers and content text.
headingLevelTimelineHeadingLevel1 | 2 | 3 | 4 | 5 | 6none
Renders the titles as h1 to h6. Without it, they are paragraphs.
localestringnone
Locale the dates are written in. Defaults to the design system locale.
formatOptionsIntl.DateTimeFormatOptionsnone
Intl.DateTimeFormat options for days and moments. Years and months keep their format.
VTimelineItem
PropTypeDefault
datetimestringnone
ISO year, month, day or moment, written out in the locale inside a <time>.
timeTextstringnone
Visible text replacing the written-out date.
titlestringnone
What happened. Replaced by the title slot.
toneTimelineItemTone'neutral' | 'accent' | 'danger' | 'success' | 'warning''accent'
Colour of the marker.
iconIconSourcenone
Icon drawn in a round badge in place of the dot.

Slots

VTimeline
SlotType
default{}
VTimelineItem children.
VTimelineItem
SlotType
default{}
Details of the event.
title{}
Title with markup.
marker{}
Replaces the dot or the badge. It is decoration.

Types

Types used in the API tables. Import exported types from vectis-ui.

export interface BuiltinIcon {
  name: string
  paths: readonly [string] | readonly [string, string]
}
export type IconRender =
  | { path: string; viewBox?: string }
  | { component: Component; props?: Record<string, unknown> }
  | { src: string }
  | { text: string; class?: string }
  | { class: string }
export type IconSource = string | BuiltinIcon | IconRender

CSS variables

TokenValue
--vectis-control-size-timeline-dot-sm0.5rem
--vectis-control-size-timeline-dot-md0.625rem
--vectis-control-size-timeline-icon-sm1.5rem
--vectis-control-size-timeline-icon-md2rem
--vectis-control-size-timeline-item-min12rem