ComponentsTimeline
Timeline
componentVertical events with state dots — activity feeds, build history, version logs.
Release progress
Where v2.4.0 is in the pipeline.
- v2.4.0 deployed2 min agoProduction · 12 services updated
- Running testsin progress348 / 412 passed
- Build artifactsPending — waits on test pass
- Notify subscribers
Composes: Avatar · Badges & pills
Recipe CSS
This is the exact CSS your kit ships for Timeline — token-driven, so it re-themes with every knob. Get it (and the rest) from the configurator's Use kit panel.
/* === Timeline (Tier 4 #17) ===========================================
* Verticale events met dots + connecting line. De line is een ::before
* pseudo-element die door alle items loopt; eindigt op het laatste item.
* Dots: filled (done), pulse-ring (current), hollow (future). */
.timeline {
list-style: none;
margin: 0;
padding: 0;
position: relative;
}
.timeline::before {
content: '';
position: absolute;
left: 10px;
top: 10px;
bottom: 10px;
width: 1.5px;
background: var(--k-border);
}
.timeline__item {
position: relative;
display: flex;
gap: var(--k-s-14);
padding: var(--k-s-6) 0;
z-index: 1;
}
.timeline__dot {
flex-shrink: 0;
width: calc(var(--k-in-h-default) - 0.875rem);
height: calc(var(--k-in-h-default) - 0.875rem);
border-radius: 50%;
background: var(--k-surface);
border: max(1.5px, var(--k-bw)) solid var(--k-border);
display: grid;
place-items: center;
color: var(--k-fg-muted);
margin-top: 1px;
}
.timeline__dot svg { width: var(--k-icon-xs); height: var(--k-icon-xs); }
.timeline__item--done .timeline__dot {
background: var(--k-primary);
border-color: transparent;
color: var(--k-primary-fg);
}
.timeline__item--current .timeline__dot {
background: var(--k-surface);
border-color: var(--k-primary);
position: relative;
}
/* The not-yet / future state (the 3rd checklist step beside --done / --current),
so a status tracker reads done › current › upcoming without hand-rolled greys. */
.timeline__item--upcoming .timeline__title { color: var(--k-fg-muted); }
.timeline__item--upcoming .timeline__dot { color: var(--k-fg-faint); }
.timeline__pulse {
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--k-primary);
position: relative;
}
.timeline__pulse::after {
content: '';
position: absolute;
inset: -4px;
border-radius: 50%;
background: var(--k-primary);
opacity: 0.25;
animation: timeline-pulse 1.6s ease-in-out infinite;
}
@keyframes timeline-pulse {
0%, 100% { transform: scale(1); opacity: 0.25; }
50% { transform: scale(1.6); opacity: 0; }
}
.timeline__body { flex: 1; min-width: 0; padding-bottom: var(--k-s-4); }
.timeline__head {
display: flex;
align-items: baseline;
justify-content: space-between;
gap: var(--k-s-8);
}
.timeline__title { font-size: var(--k-type-body); font-weight: var(--k-weight-semibold); color: var(--k-fg); }
.timeline__time {
font-size: var(--k-type-caption);
color: var(--k-fg-faint);
font-variant-numeric: tabular-nums;
white-space: nowrap;
}
.timeline__desc { font-size: var(--k-type-small); color: var(--k-fg-muted); margin-top: var(--k-s-2); }