Activity Timeline .mv-activity-timeline
Cronología vertical en CSS puro sobre un <ol> nativo: punto, icono, iniciales o avatar como marcadores en cinco tonos, conectores que se detienen antes de cada marcador y pasan a discontinuos hacia los pasos previstos, un marcador “en curso” pulsante, agrupación por día, y diseños alterno y compacto que se adaptan al ancho del contenedor.
| Categoría | Visualización de datos |
|---|---|
| Tipo | CSS puro (.mv-activity-timeline) |
| Estado | estable |
| Keywords | timeline, activity, activity feed, history, order history, order tracking, changelog, audit log, vertical timeline, events, feed |
When to use
- An order, a ticket or a shipment must show what happened and when, with the current status and the steps still to come
- A product changelog or release history lists versions by date with a short note for each one
- A side panel shows who did what on a project, grouped by day, with comments and attached files
- An audit or account log lists dated events with a clear tone for successes, warnings and failures
Avoid when
- Users must work through the steps of a process themselves, such as a wizard or onboarding → use Stepper instead
- The need is a time ruler with a playhead for video, audio or animation editing → use Timeline Scrubber instead
- The feed updates in real time and new entries should slide in as they arrive → use Animated List instead
Instalación
node scripts/add.mjs activity-timeline --out ./src/marvelousAgente de IA con el servidor MCP de Marvelous UI: install_components({ slugs: ["activity-timeline"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).
Archivos copiados (dependencias incluidas): tokens/tokens.css, core/base.css, components/activity-timeline/activity-timeline.css.
Uso
Marcado de referencia: parte de él y personalízalo con atributos, data-* y variables CSS:
<div id="mv-at-demo" style="display:grid;gap:1.25rem;width:100%">
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,22rem),1fr));gap:1.25rem;align-items:start">
<!-- Order history: icons, tones, a step in progress, upcoming steps -->
<section class="mv-card" aria-labelledby="mv-at-order-title">
<div class="mv-card-header" style="display:flex;align-items:start;justify-content:space-between;gap:1rem">
<div>
<h3 class="mv-card-title" id="mv-at-order-title">Order #MV-48213</h3>
<p class="mv-card-description">Placed Sep 22, 2026 · 3 items · $248.00</p>
</div>
<span class="mv-badge" data-variant="info">In transit</span>
</div>
<div class="mv-card-content">
<ol class="mv-activity-timeline" role="list" aria-label="Order history">
<li class="mv-activity-timeline-item" data-tone="success">
<span class="mv-activity-timeline-marker" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
</span>
<div class="mv-activity-timeline-body">
<time class="mv-activity-timeline-time" datetime="2026-09-22T10:14">Sep 22, 2026, 10:14 AM</time>
<h4 class="mv-activity-timeline-title">Order placed</h4>
<p class="mv-activity-timeline-description">Paid with Visa ending in 4242.</p>
</div>
</li>
<li class="mv-activity-timeline-item" data-tone="success">
<span class="mv-activity-timeline-marker" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 8 12 3 3 8v8l9 5 9-5z"/><path d="m3 8 9 5 9-5M12 13v8"/></svg>
</span>
<div class="mv-activity-timeline-body">
<time class="mv-activity-timeline-time" datetime="2026-09-23T16:02">Sep 23, 2026, 4:02 PM</time>
<h4 class="mv-activity-timeline-title">Shipped</h4>
<p class="mv-activity-timeline-description">Left the Rotterdam warehouse with DHL Express.</p>
</div>
</li>
<li class="mv-activity-timeline-item" data-tone="warning">
<span class="mv-activity-timeline-marker" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4M12 17h.01"/><path d="M10.3 3.9 1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z"/></svg>
</span>
<div class="mv-activity-timeline-body">
<time class="mv-activity-timeline-time" datetime="2026-09-24T08:30">Sep 24, 2026, 8:30 AM</time>
<h4 class="mv-activity-timeline-title">Held at customs</h4>
<p class="mv-activity-timeline-description">Cleared after 6 hours. New estimate: <strong>Sep 26</strong>.</p>
</div>
</li>
<li class="mv-activity-timeline-item" data-state="current" aria-current="step">
<span class="mv-activity-timeline-marker" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 6h12v10H2z"/><path d="M14 9h4.5L22 12.5V16h-8"/><circle cx="6.5" cy="17.5" r="1.75"/><circle cx="17.5" cy="17.5" r="1.75"/></svg>
</span>
<div class="mv-activity-timeline-body">
<time class="mv-activity-timeline-time" datetime="2026-09-25T07:48">Sep 25, 2026, 7:48 AM</time>
<h4 class="mv-activity-timeline-title">In transit to Chicago, IL</h4>
<div class="mv-activity-timeline-content">
<div class="mv-activity-timeline-card" style="display:flex;align-items:center;justify-content:space-between;gap:.75rem;flex-wrap:wrap">
<div style="min-width:0">
<div style="color:var(--mv-fg-muted);font-size:var(--mv-text-xs)">DHL tracking number</div>
<div style="font-family:var(--mv-font-mono);font-size:var(--mv-text-xs);overflow-wrap:anywhere">JD014600006281234567</div>
</div>
<a class="mv-button" data-variant="outline" data-size="sm" href="#mv-at-order-title">Track package</a>
</div>
</div>
</div>
</li>
<li class="mv-activity-timeline-item" data-state="upcoming">
<span class="mv-activity-timeline-marker" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m3 11 9-7 9 7"/><path d="M5 10v10h14V10"/><path d="M10 20v-6h4v6"/></svg>
</span>
<div class="mv-activity-timeline-body">
<time class="mv-activity-timeline-time" datetime="2026-09-26">Expected Sep 26, 2026</time>
<h4 class="mv-activity-timeline-title">Delivery</h4>
<p class="mv-activity-timeline-description">Signature required at 1450 W Randolph St.</p>
</div>
</li>
</ol>
</div>
</section>
<!-- Activity log: compact, grouped by day, avatars -->
<section class="mv-card" aria-labelledby="mv-at-activity-title">
<div class="mv-card-header">
<h3 class="mv-card-title" id="mv-at-activity-title">Activity</h3>
<p class="mv-card-description">Atlas redesign</p>
</div>
<div class="mv-card-content">
<ol class="mv-activity-timeline" data-variant="compact" role="list" aria-label="Project activity">
<li class="mv-activity-timeline-group">
<h4 class="mv-activity-timeline-heading" id="mv-at-today">Today</h4>
<ol role="list" aria-labelledby="mv-at-today">
<li class="mv-activity-timeline-item">
<span class="mv-activity-timeline-marker"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23fde68a'/%3E%3Cstop offset='1' stop-color='%23d97706'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%231f2937'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23e7b590'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23e7b590'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%237c2d12'/%3E%3C/svg%3E" alt=""></span>
<div class="mv-activity-timeline-body">
<div class="mv-activity-timeline-header">
<p class="mv-activity-timeline-title"><strong>Aiko Tanaka</strong> commented on <a href="#mv-at-activity-title">Checkout flow v3</a></p>
<time class="mv-activity-timeline-time" datetime="2026-09-25T10:42">10:42 AM</time>
</div>
<div class="mv-activity-timeline-content">
<blockquote><p>Can we keep the promo code field collapsed by default? It pushes the Pay button below the fold on small phones.</p></blockquote>
</div>
</div>
</li>
<li class="mv-activity-timeline-item">
<span class="mv-activity-timeline-marker"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%2399f6e4'/%3E%3Cstop offset='1' stop-color='%230f766e'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%23f8fafc'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%23b98363'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%23b98363'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%231c1917'/%3E%3C/svg%3E" alt=""></span>
<div class="mv-activity-timeline-body">
<div class="mv-activity-timeline-header">
<p class="mv-activity-timeline-title"><strong>Mateo Álvarez</strong> uploaded 2 files</p>
<time class="mv-activity-timeline-time" datetime="2026-09-25T09:15">9:15 AM</time>
</div>
<div class="mv-activity-timeline-content">
<ul class="mv-activity-timeline-attachments" role="list">
<li><a class="mv-activity-timeline-attachment" href="#mv-at-activity-title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 3H6a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V8z"/><path d="M14 3v5h5"/></svg>checkout-mobile.fig <small>4.2 MB</small></a></li>
<li><a class="mv-activity-timeline-attachment" href="#mv-at-activity-title"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 3H6a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V8z"/><path d="M14 3v5h5M9 13h6M9 17h4"/></svg>user-test-notes.pdf <small>860 KB</small></a></li>
</ul>
</div>
</div>
</li>
<li class="mv-activity-timeline-item" data-tone="success">
<span class="mv-activity-timeline-marker" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round"><path d="M20 6 9 17l-5-5"/></svg>
</span>
<div class="mv-activity-timeline-body">
<div class="mv-activity-timeline-header">
<p class="mv-activity-timeline-title"><strong>Deploy #1284</strong> to staging succeeded</p>
<time class="mv-activity-timeline-time" datetime="2026-09-25T08:03">8:03 AM</time>
</div>
</div>
</li>
</ol>
</li>
<li class="mv-activity-timeline-group">
<h4 class="mv-activity-timeline-heading" id="mv-at-yesterday">Yesterday</h4>
<ol role="list" aria-labelledby="mv-at-yesterday">
<li class="mv-activity-timeline-item">
<span class="mv-activity-timeline-marker"><img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 64 64'%3E%3Cdefs%3E%3ClinearGradient id='g' x1='0' y1='0' x2='1' y2='1'%3E%3Cstop offset='0' stop-color='%23fecdd3'/%3E%3Cstop offset='1' stop-color='%23e11d48'/%3E%3C/linearGradient%3E%3C/defs%3E%3Crect width='64' height='64' fill='url%28%23g%29'/%3E%3Cpath d='M10 66c1-12 10-19 22-19s21 7 22 19z' fill='%23fafaf9'/%3E%3Crect x='27' y='36' width='10' height='12' rx='4' fill='%238d5a3b'/%3E%3Ccircle cx='32' cy='27' r='11' fill='%238d5a3b'/%3E%3Cpath d='M20.5 26c0-8 5-13 11.5-13s11.5 5 11.5 13c-2-4-6-6.5-11.5-6.5S22.5 22 20.5 26z' fill='%23111827'/%3E%3C/svg%3E" alt=""></span>
<div class="mv-activity-timeline-body">
<div class="mv-activity-timeline-header">
<p class="mv-activity-timeline-title"><strong>Priya Nair</strong> moved <a href="#mv-at-activity-title">Payment errors</a> to In review</p>
<time class="mv-activity-timeline-time" datetime="2026-09-24T17:37">5:37 PM</time>
</div>
</div>
</li>
<li class="mv-activity-timeline-item" data-tone="danger">
<span class="mv-activity-timeline-marker" aria-hidden="true"></span>
<div class="mv-activity-timeline-body">
<div class="mv-activity-timeline-header">
<p class="mv-activity-timeline-title"><strong>Build #1283</strong> failed on main</p>
<time class="mv-activity-timeline-time" datetime="2026-09-24T14:10">2:10 PM</time>
</div>
<p class="mv-activity-timeline-description">3 tests failed in cart.spec.ts</p>
</div>
</li>
<li class="mv-activity-timeline-item" data-tone="accent">
<span class="mv-activity-timeline-marker" aria-hidden="true"><span>KO</span></span>
<div class="mv-activity-timeline-body">
<div class="mv-activity-timeline-header">
<p class="mv-activity-timeline-title"><strong>Kwame Osei</strong> joined the project</p>
<time class="mv-activity-timeline-time" datetime="2026-09-24T11:20">11:20 AM</time>
</div>
</div>
</li>
</ol>
</li>
</ol>
</div>
</section>
</div>
<!-- Changelog: alternates on wide containers, stacks on the left below 40rem -->
<section class="mv-card" aria-labelledby="mv-at-changelog-title">
<div class="mv-card-header">
<h3 class="mv-card-title" id="mv-at-changelog-title">Changelog</h3>
<p class="mv-card-description">What shipped in Atlas this quarter.</p>
</div>
<div class="mv-card-content">
<ol class="mv-activity-timeline" data-variant="alternate" role="list" aria-label="Releases">
<li class="mv-activity-timeline-item" data-state="current">
<span class="mv-activity-timeline-marker" aria-hidden="true"></span>
<div class="mv-activity-timeline-body">
<time class="mv-activity-timeline-time" datetime="2026-09-25">Rolling out now</time>
<h4 class="mv-activity-timeline-title">Bulk editing <span class="mv-badge" data-variant="secondary">v3.3.0</span></h4>
<p class="mv-activity-timeline-description">Select up to 500 rows and change owner, status or due date in one go. Reaching all workspaces by Sep 30.</p>
</div>
</li>
<li class="mv-activity-timeline-item" data-tone="accent">
<span class="mv-activity-timeline-marker" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3.5 14.4 9l5.6.6-4.2 3.8 1.2 5.6L12 16.1 7 19l1.2-5.6L4 9.6 9.6 9z"/></svg>
</span>
<div class="mv-activity-timeline-body">
<time class="mv-activity-timeline-time" datetime="2026-09-18">Sep 18, 2026</time>
<h4 class="mv-activity-timeline-title">Saved views <span class="mv-badge" data-variant="secondary">v3.2.0</span></h4>
<p class="mv-activity-timeline-description">Keep your filters, sorting and columns, then share the view with a link.</p>
<div class="mv-activity-timeline-content">
<ul>
<li>Pin up to 10 views in the sidebar</li>
<li>Views follow the workspace time zone</li>
</ul>
</div>
</div>
</li>
<li class="mv-activity-timeline-item" data-tone="success">
<span class="mv-activity-timeline-marker" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M13 2 4 14h7l-1 8 9-12h-7z"/></svg>
</span>
<div class="mv-activity-timeline-body">
<time class="mv-activity-timeline-time" datetime="2026-09-04">Sep 4, 2026</time>
<h4 class="mv-activity-timeline-title">Exports 4x faster <span class="mv-badge" data-variant="secondary">v3.1.2</span></h4>
<p class="mv-activity-timeline-description">CSV and Excel exports of 100,000 rows now finish in under 8 seconds.</p>
</div>
</li>
<li class="mv-activity-timeline-item" data-tone="danger">
<span class="mv-activity-timeline-marker" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3 4 6v6c0 4.5 3.4 8 8 9 4.6-1 8-4.5 8-9V6z"/><path d="m9 12 2 2 4-4"/></svg>
</span>
<div class="mv-activity-timeline-body">
<time class="mv-activity-timeline-time" datetime="2026-08-27">Aug 27, 2026</time>
<h4 class="mv-activity-timeline-title">Security update <span class="mv-badge" data-variant="secondary">v3.1.1</span></h4>
<p class="mv-activity-timeline-description">Sessions now expire after 12 hours of inactivity. Please update self-hosted installs.</p>
</div>
</li>
</ol>
</div>
</section>
</div>API
Attributes
| Name | Tipo | Default | Description |
|---|---|---|---|
data-variant | alternate | compact | (left-aligned) | On .mv-activity-timeline. alternate: entries on both sides of a centered rail, dates facing the text, once the list is at least 40rem wide (container query), left-aligned below. compact: smaller markers and tighter spacing, for side panels. |
data-tone | neutral | accent | success | warning | danger | neutral | On an entry or on its marker: color of the dot or the icon disc (soft tint). |
data-state | current | upcoming | On an entry. current: solid marker with a halo and a pulsing ring (static under reduced motion); aria-current="step" has the same effect. upcoming: hollow marker, muted title, dashed connector leading to it. | |
data-side | start | end | On an entry, in the alternate layout: forces its side instead of the automatic alternation. |
CSS classes
| Name | Description |
|---|---|
mv-activity-timeline | On an <ol> (or <ul>) with role="list". Its children are entries, or day groups. |
mv-activity-timeline-item | One entry (<li>): a marker and a body side by side, joined to the next entry by a connector. |
mv-activity-timeline-marker | The marker. Empty: a dot. With an <svg>: an icon disc. With a <span>: initials. With an <img alt="">: an avatar. Add aria-hidden="true" when it is decorative. |
mv-activity-timeline-body | Text column: time, title, description, content, in any order. |
mv-activity-timeline-time | On a <time datetime>: date or time, muted and tabular. |
mv-activity-timeline-title | Entry title (heading or <p>); may hold <strong>, links and a .mv-badge. |
mv-activity-timeline-header | Optional row holding the title and the time side by side (activity feed style); wraps on narrow widths. |
mv-activity-timeline-description | Secondary text under the title. |
mv-activity-timeline-content | Free content under the text: a card, a <blockquote> (styled as a quoted comment), a <ul> of notes, attachments. |
mv-activity-timeline-card | Framed box for details inside the content (tracking number, summary, diff). |
mv-activity-timeline-attachments | Row of attachment chips (<ul role="list">). |
mv-activity-timeline-attachment | One file chip (<a> or <span>): an icon, a name and an optional <small> for the size. |
mv-activity-timeline-group | A day group (<li>): a .mv-activity-timeline-heading followed by a nested <ol> of entries. Each group has its own rail. |
mv-activity-timeline-heading | Group label (Today, Sep 24, 2026…), with a hairline after it; a centered pill in the alternate layout. |
CSS variables
| Name | Default | Description |
|---|---|---|
--mv-activity-timeline-marker-size | 2rem (compact: 1.5rem) | Width of the marker column and size of icon, initials and avatar markers. |
--mv-activity-timeline-dot-size | 0.75rem (compact: 0.5rem) | Size of plain dot markers. |
--mv-activity-timeline-gap | 0.875rem (compact: 0.625rem) | Space between the marker column and the text. |
--mv-activity-timeline-space | 1.5rem (compact: 1rem) | Vertical space between entries. |
--mv-activity-timeline-line | var(--mv-border) | Connector color. |
--mv-activity-timeline-line-width | 2px (compact: 1.5px) | Connector thickness. |
Accessibility
A native ordered list: put role="list" on the <ol> (and on nested group lists) so Safari keeps list semantics without bullets, and give it an aria-label or aria-labelledby. Each date is a <time datetime> with the full date in visible text or in its datetime. Markers carry no meaning on their own: mark them aria-hidden="true" (or give avatars alt=""), and write the status in the title or a badge, never with color alone. For the step in progress, add aria-current="step" (it also applies the current styling). Day groups are nested lists labelled by their heading. The pulsing ring stops under reduced motion (OS setting or data-motion="reduce") and in print; the static halo stays so the current step is still marked. In forced colors, connectors and markers use CanvasText and the current marker gets a Highlight outline. Logical properties throughout, so the rail sits on the right in right-to-left pages. No JavaScript and nothing focusable except the links you add.