Línea de tiempo
Eventos dispuestos en orden cronológico, cada uno con un marcador, su momento, un título y un cuerpo con tu contenido, unido al siguiente por una línea fina. Donde los eventos tienen un estado, la forma del marcador y tus palabras dicen cuáles están hechos, cuál está en curso y cuáles quedan por delante. Es una lista para leer, nunca un control.
- Categoría
- Contención
- Tokens
comp.timeline- Nivel
- Base
- Web
tanrei-timelineschedule - SwiftUI
TanreiTimelineradio_button_unchecked - Jetpack Compose
TanreiTimelineradio_button_unchecked - Flutter
TanreiTimelineradio_button_unchecked - React Native
Timelineradio_button_unchecked
Generado a partir de docs/status/status.json, specs/timeline.spec.json
Un registro de lo que ocurrió
Estilos de texto por nivel
Los estilos de texto se nombran por su nivel, y todas las esquinas se pueden suavizar.
Un vocabulario que se puede extender
Una capa de diseño puede añadir un paso a una serie o un valor a un eje, con su motivo.
Comienza el desarrollo
Ya existen la cadena de tokens, el esquema de las especificaciones y la primera especificación.
Hay tres cosas que se dibujan como marcas unidas por una línea. Se diferencian en lo que quien lee hace con ellas:
| Componente | Qué es | El marcador | Qué dice del estado | Recibe entrada |
|---|---|---|---|---|
| Unos pasos | Un procedimiento que hay que llevar a cabo | Un anillo con el número del paso | Nada | Nunca |
| Una línea de tiempo | Un registro de lo que ocurrió y de lo que está por venir | Un punto o un glifo, nunca un número | Opcionalmente, en qué situación está cada evento | Nunca |
| Un indicador de pasos (stepper) | En qué punto está una persona de un flujo que dirige el producto | Un número o una marca de verificación | El punto en que está la propia persona | Sí |
Una línea de tiempo nunca numera, ordena ni oculta sus eventos, y no lee sus momentos. El orden es el que tú das.
En la web la línea de tiempo es una clase en tu propia lista ordenada, no un elemento. La lista es la del documento, con sus elementos <time>, antes de que se ejecute ningún script, y sin la hoja de estilos es la lista numerada del navegador, hecha de párrafos con fecha.
SwiftUI, Compose, Flutter y React Native están planificados: los nombres que figuran junto a cada plataforma al principio de esta página son los que les da la especificación, y todavía no se distribuye nada para ellos. React tampoco tiene aún un componente Timeline, así que usa la lista con la clase.
<link rel="stylesheet" href="@tanrei/web/tokens.css" />
<link rel="stylesheet" href="@tanrei/web/icons.css" />
<link rel="stylesheet" href="@tanrei/web/timeline.css" />
<!-- Un registro: eventos que simplemente ocurrieron. -->
<ol class="tanrei-timeline" role="list" aria-label="Historial de versiones">
<li>
<time class="tanrei-timeline-time" datetime="2026-09-19">19 de septiembre de 2026</time>
<p class="tanrei-timeline-title">Comienza el desarrollo</p>
<p>Ya existen la cadena de tokens, el esquema de las especificaciones y la primera especificación.</p>
</li>
</ol>
<!-- Un plan: cada evento tiene un estado, en una forma y en tus palabras. -->
<ol class="tanrei-timeline" role="list" data-size="large" aria-label="Hoja de ruta">
<li data-status="done" data-status-label="Completado">
<!-- No es un instante: un párrafo, no un elemento time. -->
<p class="tanrei-timeline-time">Wave 1</p>
<!-- Un título que es un encabezado de la página: conserva su rol y su nivel. -->
<h3 id="wave-1">Los controles del primer día</h3>
<p>Botones, campos, controles de selección y la lista.</p>
</li>
<li data-status="current" data-status-label="En curso">
<p class="tanrei-timeline-time">Wave 2</p>
<h3 id="wave-2">Navegación y superposiciones</h3>
</li>
<li data-status="upcoming" data-status-label="Sin empezar">
<!-- Tu propio glifo en el marcador. -->
<span class="tanrei-timeline-marker tanrei-icon" aria-hidden="true">flag</span>
<p class="tanrei-timeline-time">Wave 3</p>
<h3 id="wave-3">Las piezas especializadas</h3>
</li>
</ol>
<script type="module">
// Opcional: marca el único evento en curso como el elemento actual de la lista y añade los informes de depuración.
// `@tanrei/web` también lo carga.
import '@tanrei/web/timeline';
</script>import '@tanrei/web/timeline.css';
import '@tanrei/web/timeline';
<ol className="tanrei-timeline" role="list" aria-label="Historial de versiones">
<li>
<time className="tanrei-timeline-time" dateTime="2026-09-19">19 de septiembre de 2026</time>
<p className="tanrei-timeline-title">Comienza el desarrollo</p>
<p>Ya existen la cadena de tokens, el esquema de las especificaciones y la primera especificación.</p>
</li>
</ol>| Propiedad | En la web |
|---|---|
label |
aria-label (o aria-labelledby con el encabezado que precede a la lista) |
size: large |
data-size="large" |
density: compact |
data-density="compact" |
| un evento | <li> |
time con datetime |
<time class="tanrei-timeline-time" datetime="…">, que contiene las palabras que escribes tú |
un time que no es un instante |
<p class="tanrei-timeline-time"> |
title |
un elemento con class="tanrei-timeline-title" (un <p>) |
| el slot del título | un encabezado (de h2 a h6) que abre el evento o que sigue a su momento |
status |
data-status="done", "current" o "upcoming" |
statusLabel |
data-status-label |
icon |
<span class="tanrei-timeline-marker tanrei-icon" aria-hidden="true"> como primer hijo del elemento de lista |
Escribe role="list" en la lista: un motor de navegador retira la semántica de lista de una lista a la que se le quitan los marcadores.
El momento es tuyo. Escríbelo en el idioma, el calendario y el formato de quien lee, y pon ese mismo instante en datetime para las máquinas. La línea de tiempo no da formato a nada: «hace 2 horas» se queda como está escrito hasta que lo cambies tú.
Un plan: hecho, hecho, en curso, por delante
Wave 0
Fundamentos
Tokens, temas, tipografía, iconos, superficies y las primitivas de estado.
Wave 1
Los controles del primer día
Botones, campos, controles de selección y la lista.
Wave 2
Navegación y superposiciones
El panel de navegación, las pestañas, los diálogos, los menús y las hojas.
Wave 3
Las piezas especializadas
Los selectores, el carrusel y lo que necesita un sitio de documentación.
Tus propios glifos, y un registro compacto
Lunes, 09:41
Pedido realizado
Martes, 14:05
En camino
Previsto para el jueves
Entregado
Capa guardada
Contraste comprobado en seis esquemas
Color primario cambiado
- El marcador está en una caja situada en el borde de inicio, de 24 de lado a lado en medium y de 28 en large, centrada en la primera línea del evento. Sin estado es un punto pequeño; con un glifo tuyo es un anillo de línea fina que contiene el glifo.
- Un estado cambia la forma del marcador y nada más: un anillo con una marca de verificación para el evento hecho, un círculo relleno con un punto para el que está en curso y un anillo vacío para el que todavía queda por delante. El círculo relleno es el único color que aporta una línea de tiempo, aparte del color del momento.
- El conector va de la caja de cada marcador a la siguiente y se detiene antes de tocar ninguna de las dos. El último evento no tiene, y es la misma línea entre eventos de cualquier estado.
- El momento va primero en el evento, en un color discreto. El título lo sigue, con el tamaño del cuerpo y un peso de título. El cuerpo es tu contenido: dos bloques quedan a 8 uno de otro.
- La densidad: regular pone 16 entre dos eventos, y compact, 8, para un registro largo de eventos de una línea. Solo cambia ese espacio.
- Los tamaños son los dos de la prosa: medium entre controles, large en una página cuya finalidad es el texto. El marcador y el conector coinciden con los de los pasos, así que en una misma página los dos se leen como una sola familia.
Anatomía
| Parte | Descripción |
|---|---|
1 list | The ordered list itself: one column of events, as wide as its container gives it. It has no fill, no edge, no padding and no state of its own. |
2 item | One event: its marker at the start, and beside it its content — a time, a title and a body, each optional. Nothing about an event answers a pointer, a press or focus. |
3 marker | What begins an event, centred in a box at the start edge. A small filled dot for an event with no status; a hairline ring holding a glyph where the product names one; and for an event with a status a shape of its own: a ring holding a check for done, a filled circle holding a dot for the one under way, an empty ring for one still ahead. Decorative: the status is given in words. |
4 connector · opcional | The line from an event's marker to the next event's: the system's one hairline, on the marker column's centre line, kept a small distance from both markers. It shows that the events are one course of time. Decorative. The last event has none. |
5 time · opcional | When the event happened or is due, as the product writes it ("19 September 2026", "09:41", "Q3", "Wave 1"): a short line in a quiet color, first in the event's content. |
6 title · opcional | What the event is, in a few words, set at the body's size in a heading weight. Text of its event and not a heading, unless the product gives a heading of its own as the title. |
7 body · opcional | What more there is to say: the product's content. Text placed directly takes the body's text style; long-form blocks are set as prose; a block that is not text takes the body's whole width. |
Propiedades
| Propiedad | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
label | string | "" | The list's accessible name, in the product's language ("Release history"). Not drawn. Give one where no heading directly before the timeline already says what it records. |
size | medium | large | "medium" | The size of the events' text, in prose's two sizes. Medium sets the body in the interface's own text style, for a timeline among controls: a panel, a card, a record's activity. Large sets it in the style for long reading, for a page whose purpose is the text: a changelog, a plan. A timeline inside a prose is given that prose's size. A design system may add values. |
density | regular | compact | "regular" | How far apart the events are. Regular is for events with a body, or few of them. Compact halves the space between events, for a long log of one-line events. It changes that space only. A design system may add values. |
Elementos
Los tipos de elemento que el componente repite. Un fixture enumera sus elementos en orden; cada plataforma nombra cada tipo según su propio estilo.
event
One event of the timeline: a time, a title, a body, and where the events have them a status and a glyph. Its place comes from the order the product gives the events in.
| Propiedad | Tipo | Valor predeterminado | Descripción |
|---|---|---|---|
time | string | "" | When, as the product writes it for its reader, in the product's language, calendar and format ("19 September 2026", "2 hours ago", "Q3", "Wave 1"). Drawn first in the event. The timeline does not format, translate or compare it. |
datetime | string | "" | The same moment for a machine: a date, a time or a period in the form the platform's time element takes (ISO 8601: "2026-09-19", "2026-09-19T09:41:00Z"). Not drawn. With it the time is exposed as a time; without it, as text — which is right for a time that is not a moment ("Wave 1"). |
title | string | "" | What the event is, in a few words. Plain text: read with the event, and not a heading. A title that is a heading of the page is given in the title slot instead. |
status | none | done | current | upcoming | "none" | Where the event stands, for a timeline whose events have a state: done (finished), current (under way now), upcoming (not begun). None, the default, is an event that simply happened: a log has no statuses. It changes the marker's shape and nothing else; the words are statusLabel's. |
statusLabel | string | "" | The status in words, in the product's language ("Done", "In progress", "Planned"), read by assistive technology before the event's time and title and not drawn. Needed with every status but none, unless the event's own text already says it. Ignored while status is none. |
icon | string | "" | A glyph of the system's icon set, by name, drawn in the marker in place of the dot, the check or the inner mark (a release's tag, a comment's bubble). Decorative. |
| Slot | Descripción |
|---|---|
title | The title as content of the product's own: a heading of the level the page's outline needs (so the event is in the page's table of contents and can be linked to), or text with a link or a tag in it. Drawn in the title's text style whatever its level; its role and level are kept. Takes the place of the title prop. |
| Especificación | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
|---|---|---|---|---|---|
| Elemento | li | TanreiTimelineEvent | TanreiTimelineEvent | TanreiTimelineEvent | TimelineEvent |
time · Propiedad | tanrei-timeline-time | time | time | time | time |
datetime · Propiedad | datetime | date | dateTime | dateTime | dateTime |
title · Propiedad | tanrei-timeline-title | title | title | title | title |
status · Propiedad | data-status | status | status | status | status |
statusLabel · Propiedad | data-status-label | statusLabel | statusDescription | statusSemanticLabel | statusAccessibilityLabel |
icon · Propiedad | tanrei-timeline-marker | icon | icon | icon | icon |
| Notas | An <li> of the list. The time is the item's <time class="tanrei-timeline-time" datetime="…">, or a <p> of that class where it is not a moment. The title is the next child where it is a heading (h2 to h6) or carries class="tanrei-timeline-title": the spec's title prop and its title slot are the same element on this platform, told apart by the tag the product chose. Every other child is the body. data-status is done, current or upcoming; data-status-label carries the words. A glyph is <span class="tanrei-timeline-marker tanrei-icon" aria-hidden="true">flag</span> as the item's first child. | TanreiTimelineEvent(title:, time:, date:, status:, statusLabel:, icon:) { body }; a heading title is the title: view builder, marked with the header trait by the product. | TanreiTimelineEvent(title, time, dateTime, status, statusDescription, icon) { body } inside the timeline's scope. | TanreiTimelineEvent(title:, time:, dateTime:, status:, statusSemanticLabel:, icon:, child:); titleWidget: takes a heading of the product's own. | <TimelineEvent title="…" time="…" status="done" statusAccessibilityLabel="Done">body</TimelineEvent>. |
Estados
Comportamiento
Requisitos en formato EARS. Cada implementación de plataforma se prueba contra estos identificadores. El texto de los requisitos se muestra tal como está en la especificación, en inglés.
| ID | Requisito |
|---|---|
TML-1 | THE timeline SHALL lay out its events in one column, in the order they are given, each event a row of two parts: its marker, in a column at the timeline's start edge, and its content — its time, its title and its body, those it has, in that order — beside it. The marker column SHALL be as wide as the marker's box of the size (comp.timeline.marker.height.medium for medium, comp.timeline.marker.height.large for large); every event's content SHALL begin at one edge, comp.timeline.marker.gap after that column, and run to the timeline's end edge. THE timeline SHALL draw no fill, no edge and no elevation of its own and SHALL add no padding around itself. |
TML-2 | THE timeline SHALL separate the end of one event from the beginning of the next by the item gap of its density (comp.timeline.item.gap.regular for regular, comp.timeline.item.gap.compact for compact), and SHALL change nothing else with density. THE timeline SHALL keep the order the product gives: it SHALL NOT sort, reverse, group, number, hide, collapse or page its events, and SHALL NOT read their times to do so. |
TML-3 | WHERE an event has a time THE timeline SHALL draw it first in the event's content, as the product wrote it, in the time style of its size (comp.timeline.time.typescale.medium for medium, comp.timeline.time.typescale.large for large) and in comp.timeline.time.color, wrapping and never cut, and SHALL begin what follows it in the event comp.timeline.time.gap below it. WHERE datetime is not empty THE timeline SHALL expose the time as a time whose machine-readable value is datetime, and SHALL NOT draw datetime; WHERE it is empty the time is text. THE timeline SHALL NOT format, translate, shorten or update a time: a time that changes as the clock moves ("2 hours ago") is the product's to change. |
TML-4 | WHERE an event has a title THE timeline SHALL draw it after the time, in comp.timeline.title.typescale.medium for medium (comp.timeline.title.typescale.large for large) and the content color of the surface the timeline sits on, SHALL wrap it and never cut it, and SHALL begin the event's body comp.timeline.title.gap below it. A title given as text SHALL be exposed as text of its event and SHALL NOT be a heading; WHERE the product gives the title as content of its own in the event's title slot THE timeline SHALL draw it as any title, in the same text style whatever its level, in place of the title prop, and SHALL change neither its role nor its level, nor the roles of what it holds (a link, a tag). THE timeline SHALL set the title's letter-spacing by the script of its text, as every title is set (PRS-20): no negative letter-spacing WHERE its language is Chinese, Japanese or Korean, and none WHERE its script joins its letters or stacks marks on them. |
TML-5 | THE timeline SHALL draw the content an event is given as that event's body and SHALL give it comp.timeline.body.typescale.medium for medium (comp.timeline.body.typescale.large for large) as the text style its text takes where nothing inside sets another, and no color of its own: its text takes the content color of the surface the timeline sits on. The body SHALL wrap and SHALL never be cut or limited to a number of lines. WHERE the body holds more than one block THE timeline SHALL separate two blocks that follow each other by comp.timeline.body.gap, SHALL lay long-form blocks out as prose of the timeline's size, and SHALL give every block that is not text — a code block, a table, a picture, any component — the body's whole inline size, such a block scrolling inside its own box when its content cannot shrink (PRS-15). |
TML-6 | THE timeline SHALL draw each event's marker centred in a square box whose side is the marker's box of the size (TML-1), the box at the top of the event with its centre on the centre of the event's first line of text; WHERE the box is taller than that line THE timeline SHALL lower the event's content by half the difference, so that no marker reaches into the space above its event. WHILE an event's status is none and its icon is empty THE marker SHALL be a filled circle of diameter comp.timeline.marker.dot.size in comp.timeline.marker.dot.color, a circle whatever corners a ring has. WHILE its status is none and its icon is not empty THE marker SHALL be a ring — the whole box, with corners comp.timeline.marker.shape, never larger than half the box's side and eased by sys.shape.corner-smoothing, no fill, and an edge comp.timeline.marker.outline.width wide in comp.timeline.marker.outline.color drawn inside the box — holding that glyph at its centre (TML-8). Every marker SHALL be kept from assistive technology. |
TML-7 | WHILE an event's status is done THE timeline SHALL draw its marker as the ring of TML-6 holding the icon set's check glyph, or the event's own glyph where icon is not empty, in comp.timeline.marker.icon.color. WHILE its status is current THE marker SHALL be the whole box filled with comp.timeline.marker.current.container.color, with the ring's corners and no edge, holding a filled circle of diameter comp.timeline.marker.dot.size, or the event's own glyph, in comp.timeline.marker.current.icon.color. WHILE its status is upcoming THE marker SHALL be the ring of TML-6, empty, or holding the event's own glyph in comp.timeline.marker.icon.color. The three SHALL differ in shape and not only in color — a mark in a ring, a filled circle, an empty ring — and a status SHALL change the marker only: the event's time, title, body and connectors are drawn as every other event's. Any number of events may have any status; THE timeline SHALL NOT derive one event's status from another's or from its time. |
TML-8 | WHERE a marker holds a glyph THE timeline SHALL draw it in a box of comp.timeline.marker.icon.size at the centre of the marker, in comp.timeline.marker.icon.color (comp.timeline.marker.current.icon.color on the marker of a current event), with sys.icon.family.unselected and sys.icon.fill.unselected, sys.icon.weight and an optical size clamped between sys.icon.optical-size.min and sys.icon.optical-size.max, and SHALL keep it from assistive technology. |
TML-9 | WHILE an event is followed by another event THE timeline SHALL draw a connector between their two markers: a straight line comp.timeline.connector.thickness thick in comp.timeline.connector.color, on the centre line of the marker column, from comp.timeline.connector.gap below the bottom of the upper marker's box to comp.timeline.connector.gap above the top of the lower marker's box, through the space between the two events, however tall the upper event's content is. THE timeline SHALL draw no connector after the last event and none for a timeline of one event; a connector SHALL take no room in the layout, SHALL never be drawn over a marker or over content, SHALL be the same line between events of any status, and SHALL be kept from assistive technology. |
TML-10 | THE timeline SHALL lay itself out as a block in the flow of its container: it SHALL take the whole inline size the container gives it, with its start edge on the start edge of the text around it; it SHALL bring no outer space of its own (PRS-15: the space between it and its neighbours is its container's), SHALL never be wider than its container, SHALL have no minimum width and no maximum width, and SHALL NOT scroll. WHILE the timeline sits in a prose that keeps a measure THE timeline SHALL take that prose's full width as a block that is not text (PRS-18). |
TML-11 | THE timeline SHALL NOT take pointer, touch or keyboard input, SHALL NOT take focus or be a stop in the focus order, and SHALL NOT change anything it draws under a pointer, a press or focus: an event has no hovered, focused, pressed, selected or disabled state, a marker is not a control, and the timeline emits no event of its own. What the product places in a title slot or a body — a link, a Button, a tag — takes input by its own spec, and text in a time, a title and a body SHALL remain selectable where the platform lets text be selected. |
TML-12 | THE timeline SHALL be exposed to assistive technology as an ordered list of as many items as it has events, named by label where label is not empty, and each event as one item of that list holding, in this order, its status in words, its time, its title and its body. WHILE an event's status is not none and its statusLabel is not empty THE timeline SHALL expose statusLabel as text before the event's time, set apart so that it is read as a phrase of its own ("Done, 19 September 2026, …"), and SHALL NOT draw it; WHILE status is none it SHALL ignore statusLabel. WHILE exactly one event of the timeline has the status current THE timeline SHALL also expose that event as the current item of its list, in the platform's own way; with none or several it SHALL expose no item as current. THE timeline SHALL NOT expose a status in any other way, and SHALL add no role to a time without datetime, to a title given as text or to anything in a body. |
TML-13 | WHEN label, or an event's time, datetime, title, status, statusLabel, icon or body changes, or an event is added, removed or moved, THE timeline SHALL draw and expose the new value at once, without a motion, and SHALL NOT announce the change by itself and SHALL NOT scroll to it. |
TML-14 | WHILE the text size is enlarged THE timeline SHALL grow each time, title and body with it, keep every marker's box at the marker's box of the size and the dot and the glyph at comp.timeline.marker.dot.size and comp.timeline.marker.icon.size, each still centred on its event's first line (TML-6), and keep comp.timeline.marker.gap, the item gap, comp.timeline.time.gap, comp.timeline.title.gap, comp.timeline.body.gap and comp.timeline.connector.gap as they are; it SHALL wrap, set no fixed height on an event, lose no content when the reader raises line height, paragraph spacing, letter spacing or word spacing, and SHALL need no horizontal scrolling at a width of 320 points with text at 200 %, except inside a block that scrolls in its own box (TML-5). |
TML-15 | WHERE the timeline is placed inside an event's body of another timeline THE timeline SHALL draw itself as a timeline of its own in the body's width, and in debug builds SHALL report that timelines are nested: events inside an event are a list of prose in the body. |
TML-16 | WHERE the platform draws with a person's own forced colors (the web's forced-colors mode, and a platform's equivalent where it has one) THE timeline SHALL draw each dot, each ring, each glyph and each connector in the platform's text color at their own sizes and widths, the marker of a current event as a circle filled with that text color whose inner mark or glyph is in the platform's background color, and each time, title and body in the text color; the three statuses SHALL then still differ by shape (TML-7), and nothing else the timeline draws relies on a fill. |
TML-17 | WHERE the layout direction is right-to-left THE timeline SHALL mirror its two parts and apply its spaces by logical start and end, so that the marker column and the connectors are at the right and each event's content is at its left, beginning at one edge and running to the timeline's left edge. |
TML-18 | THE timeline SHALL take its layout direction from where it is used — the direction of the nearest ancestor that sets one, and the platform's own where none does — and SHALL have no direction setting of its own; WHEN that direction changes while the timeline is shown THE timeline SHALL draw itself for the new direction at once, without a motion of its own, keeping what it shows. |
TML-19 | WHERE the layout direction is right-to-left THE timeline SHALL draw the glyph of a marker mirrored left to right exactly when the system's icon set marks that glyph's name as mirrored or the product forces mirroring for that use, and unmirrored when the product forbids it: the icon helper mirrors the glyph inside its own box, about the box's vertical centre line, changing neither its place, size, color and fill nor the order TML-17 gives. THE timeline SHALL NOT mirror a glyph itself. The dot, the ring and the check are never mirrored. |
TML-20 | THE timeline SHALL lay out an event's time, and a title given as text, each as text of its own direction, isolated from the text around it: it takes the base direction of its first strong character, or the layout direction where it has none, so that a date written in digits, a version and a clock time keep their own order in a right-to-left layout and reorder nothing beside them; THE timeline SHALL still place the time and the title and align their lines by the layout direction, not by the text's own. The body's direction is its content's. |
TML-21 | WHEN size or density names a value that the active design system does not have THE timeline SHALL render with the default value's tokens, and WHEN an event's status names a value this spec does not have THE timeline SHALL draw that event as for none; in debug builds it SHALL report the unknown value. |
TML-22 | IF the timeline holds no event THE timeline SHALL draw nothing, take no space and expose nothing: what stands in an empty timeline's place is the product's (an empty state). IF an event has neither a time, a title nor a body THE timeline SHALL still draw its marker and count it in the list's items, and in debug builds report that an event is empty. WHILE an event's status is not none and its statusLabel is empty THE timeline SHALL still draw it and in debug builds report that a status is not given in words; IF statusLabel is not empty while status is none THE timeline SHALL ignore it and in debug builds report it. |
Correspondencia de nombres por plataforma
Paridad no significa API idénticas. Cada plataforma expresa el mismo contrato con su propio estilo.
| Especificación | Web | SwiftUI | Jetpack Compose | Flutter | React Native |
|---|---|---|---|---|---|
| Componente | tanrei-timeline | TanreiTimeline | TanreiTimeline | TanreiTimeline | Timeline |
label · Propiedad | aria-label | label | label | semanticLabel | accessibilityLabel |
size · Propiedad | data-size | size | size | size | size |
density · Propiedad | data-density | density | density | density | density |
| Notas | It is the form the steps take. A class on the product's own ordered list, not an element — <ol class="tanrei-timeline" role="list"> with <li> children — styled by one optional stylesheet of the package, @tanrei/web/timeline.css, whose selectors are wrapped in :where() so one class on the product's side wins. The list stays the document's list: it is an ordered list with <time> elements before any script runs and for whatever reads the page as built, a renderer's <ol> needs one class and no wrapper, and there is nothing to define, so nothing changes place after the page loads; without the stylesheet it is the browser's numbered list of dated paragraphs. label is aria-label (or aria-labelledby naming the heading before it); data-size="large" and data-density="compact" are the size and the density. The marker is the item's ::before — the dot, the ring, the filled circle with its inner dot, and the done event's check as the icon font's check ligature — unless the item's first child is a .tanrei-timeline-marker, which then is the marker and holds the glyph through the package's .tanrei-icon helper; the connector is the item's ::after, absolutely placed, with pointer-events: none. list-style: none removes list semantics in one engine's accessibility tree, which is why the contract writes role="list" on the <ol>. The status in words (TML-12) is generated content of the item's first text part, content: attr(data-status-label) ", ", clipped out of sight and read with the item; the test of TML-12 is run with a screen reader in each engine, and where an engine does not read it the package's script writes a visually hidden <span> instead. The same script, where it is loaded, sets aria-current="true" on the item while exactly one has data-status="current", and adds the debug reports of TML-15, TML-21 and TML-22; without it no item is exposed as current, and the words still are. A time and a title are dir="auto"-like through unicode-bidi: plaintext with physical alignment by :dir() (TML-20). TML-6 uses 1lh of the item's first line. Inside a .tanrei-prose the list is not an island (it is a class on an <ol>), so prose's own rules keep reaching each body, and timeline.css takes back from prose.css what a timeline draws itself: the list's inset, its markers, the item gap and the measure on the list. Under forced-colors: active the markers and the connector are CanvasText, and the current marker a CanvasText disc with a Canvas mark (TML-16). React: Timeline and TimelineEvent render the same <ol> and <li>; TimelineEvent takes time, dateTime, title (text, rendered as <p class="tanrei-timeline-title">) or a heading child, status, statusLabel and icon. | TanreiTimeline(label:, size:, density:) { TanreiTimelineEvent(…) … }. A VStack of rows, not a List (no row chrome, no selection). Each event is one accessibility element that contains its children, whose label begins with the status label; date is a Date handed to the element's accessibility value where the platform has a use for it. | TanreiTimeline(label, size, density) { TanreiTimelineEvent(…) … }. A Column with collectionInfo and collectionItemInfo semantics, so the events are a list of that many items; the connector is drawn behind the rows with drawBehind. No clickable and no focusable modifier. | TanreiTimeline(semanticLabel:, size:, density:, events: [TanreiTimelineEvent(…), …]). A Column, not a ListView: the timeline does not scroll (TML-10). The connector is a CustomPaint behind the rows. Each event is a Semantics(container: true) whose label begins with the status label. | <Timeline accessibilityLabel="Release history"> with <TimelineEvent> children; accessibilityRole="list" on the container. Each event is one accessible element whose label is composed from the status label, the time and the title. Follows the app's direction where an ancestor's is not known. |
Tokens
| Token | Alias de | Valor resuelto (claro) |
|---|---|---|
--tanrei-comp-timeline-body-gap | sys.space.space100 | 8px |
--tanrei-comp-timeline-connector-color | sys.color.outline-variant | |
--tanrei-comp-timeline-connector-gap | sys.space.space50 | 4px |
--tanrei-comp-timeline-connector-thickness | sys.border.hairline | 1px |
--tanrei-comp-timeline-item-gap-compact | — | 8px |
--tanrei-comp-timeline-item-gap-regular | — | 16px |
--tanrei-comp-timeline-marker-current-container-color | sys.color.primary | |
--tanrei-comp-timeline-marker-current-icon-color | sys.color.on-primary | |
--tanrei-comp-timeline-marker-dot-color | sys.color.on-surface-variant | |
--tanrei-comp-timeline-marker-dot-size | sys.space.space100 | 8px |
--tanrei-comp-timeline-marker-gap | sys.space.space150 | 12px |
--tanrei-comp-timeline-marker-height-large | — | 28px |
--tanrei-comp-timeline-marker-height-medium | — | 24px |
--tanrei-comp-timeline-marker-icon-color | sys.color.on-surface-variant | |
--tanrei-comp-timeline-marker-icon-size | sys.icon.extra-small | 16px |
--tanrei-comp-timeline-marker-outline-color | sys.color.outline-variant | |
--tanrei-comp-timeline-marker-outline-width | sys.border.hairline | 1px |
--tanrei-comp-timeline-marker-shape | sys.shape.corner.full | 9999px |
--tanrei-comp-timeline-time-color | sys.color.on-surface-variant | |
--tanrei-comp-timeline-time-gap | sys.space.space25 | 2px |
--tanrei-comp-timeline-title-gap | sys.space.space50 | 4px |
--tanrei-comp-timeline-body-typescale-large | sys.typescale.body-large | 400 16px/1.625 |
--tanrei-comp-timeline-body-typescale-medium | sys.typescale.body | 400 14px/1.5714 |
--tanrei-comp-timeline-time-typescale-large | sys.typescale.body | 400 14px/1.5714 |
--tanrei-comp-timeline-time-typescale-medium | sys.typescale.body-small | 400 13px/1.5385 |
--tanrei-comp-timeline-title-typescale-large | sys.typescale.heading-5 | 500 16px/1.5 |
--tanrei-comp-timeline-title-typescale-medium | sys.typescale.heading-6 | 500 14px/1.4286 |
Fixtures
Representaciones canónicas. Todas las plataformas capturan cada fixture con el mismo identificador para poder comparar los resultados.
size: medium (12)
dated
label: Release history items: 3 titles-only
label: Release history items: 3 plan
label: Roadmap items: 4 plan-icons
label: Order 1042 items: 3 icons
label: Activity items: 3 compact
label: Activity density: compact items: 4 long-bodies
label: The history of an account items: 2 no-time
label: What happened items: 3 single
label: Release history items: 1 dated-rtl
label: سجل الإصدارات direction: rtl items: 2 plan-rtl
label: خارطة الطريق direction: rtl items: 3 ltr-times-rtl
label: سجل الإصدارات direction: rtl items: 2 size: large (2)
large
label: Release history size: large items: 2 large-plan-compact
label: Roadmap size: large density: compact items: 3 Generado a partir de specs/timeline.spec.json, tokens/comp/timeline.tokens.json, design/tokens/
Dentro de .tanrei-prose la línea de tiempo no es una isla: los párrafos, las listas, los enlaces y el código en línea de cada cuerpo siguen siendo los de la prosa. La línea de tiempo ocupa toda la anchura de la prosa, así que un bloque de código dentro de un cuerpo ocupa la columna, y los párrafos de un cuerpo siguen deteniéndose en la medida. @tanrei/web/prose.css incluye las reglas de la línea de tiempo, así que una página de prosa no necesita una segunda hoja de estilos.
- Escribe el texto de un evento en elementos (
<p>): al texto escrito directamente en un elemento de lista no se le puede dar la separación que va debajo de un momento o de un título. - La marca de verificación de un evento hecho es el
checkdel conjunto de iconos, así que necesitaicons.cssy la fuente de iconos. Sin ellos, el anillo queda vacío. - Fuera de una prosa, un cuerpo de texto largo (listas, citas) se dispone como en cualquier otro lugar de tu página, no como prosa.
- Un tamaño o una densidad que añade un sistema de diseño se dibuja como el predeterminado hasta que ese sistema incluya una regla para él.
- Sin el script del paquete, ningún elemento se marca como el elemento actual de la lista. El estado se sigue leyendo en palabras.
- Da los eventos en el orden que espera quien lee: primero el más reciente en un registro de cambios, primero el más antiguo en un plan. La línea de tiempo lo conserva.
- Da a cada evento que tenga un estado sus palabras en
data-status-label, en el idioma de quien lee. - Donde el estado importe a todas las personas que leen, muéstralo también con palabras: un tag en el título o en el cuerpo.
- Da a un momento relativo («hace 2 horas») su instante exacto en
datetime. - Usa compact para un registro largo de eventos de una línea, y pon un botón después de la lista para mostrar los más antiguos.
- No uses una línea de tiempo para un procedimiento. Los pasos numeran lo que quien lee tiene que hacer.
- No la uses para mostrar en qué punto está una persona de un flujo en el que se encuentra: eso es un indicador de pasos, y un marcador no es un control.
- No conviertas todos los títulos en encabezados. Un registro de cambios de cuarenta eventos llenaría el esquema de la página. Usa un encabezado donde cada evento sea una sección de la página.
- No anides una línea de tiempo dentro de un evento. Los eventos que hay dentro de un evento son una lista en el cuerpo.
- No confíes solo en el marcador para decir que algo falló. Dilo con las palabras del evento y con un tag.
- Rol
list- Etiquetado
- An ordered list, named by label where the product gives one; where a heading directly before the timeline says what it records, no label is needed. Each event is a list item read as its status in words (statusLabel, where it has a status), its time, its title and its body, in that order. A time with datetime is exposed as a time; the markers and the connector are decorative and hidden. A title is text of its item, or the product's own heading where the product gave one. Where exactly one event is current, it is the list's current item.
- Objetivo mínimo
- El área de pulsación cumple el tamaño mínimo de objetivo aunque el tamaño visual sea menor. minimum 32px · pointer 44px · spacing 8px · touch 48px
Teclado
| Teclas | Acción |
|---|
Notas
- Not interactive: the timeline takes no input and no focus (TML-11), so there is no target of its own to size and minimumTarget holds trivially. What is pressable inside a title or a body meets the minimum target by its own spec.
- A status never rests on color alone (WCAG 1.4.1), and not on shape alone either. For a reader who sees, the three statuses are three shapes (TML-7), which forced colors keep (TML-16); for assistive technology each is statusLabel in words (TML-12). The component cannot tell whether an event's own text already says its status, so giving statusLabel is the product's to check. Where the status matters to every reader (a plan people decide by), show it in words too: a tag in the title or the body.
- Order is carried by structure, not by the drawing: the timeline is an ordered list (TML-12), so a reader who does not see the markers and the connector loses nothing, and a missing stylesheet costs only the look.
- A time is the product's words (TML-3). "2 hours ago" is read as written and goes stale as written; a product that shows relative times also gives datetime, so the exact moment is available to assistive technology and to the platform.
- Contrast: the timeline brings no color for a title or a body, so they have the contrast of the content color of the surface they sit on. The time, the dot and a ring's glyph are on-surface-variant, held to 4.5:1 on every surface tone by the token invariants; the current marker's mark is on-primary on primary, held to 4.5:1, and primary on every surface tone is held to 4.5:1, as primary-colored text is, so the filled marker is found on any of them. The ring and the connector are the decorative hairline and are not held to a ratio: an upcoming event's empty ring may be faint, which is why its status is also in words.
- A title is not a heading by default: a changelog of forty events would otherwise fill the page's outline. Where the events are the page's sections (one release per section), give each title as a heading in the title slot; its level is the page's, and the timeline does not change it (TML-4).
- A timeline does not announce an event that is added (TML-13). A feed that grows while the person watches is the product's to announce, in a live region around or beside the timeline, and its own to decide whether to interrupt.
- Text size, text spacing and reflow: TML-14. A long timeline is never cut, collapsed or paged by the component; hiding older events behind a control is the product's, with a Button after the list.
Generado a partir de specs/timeline.spec.json, tokens/sys/measure.tokens.json
- Sigue siendo la lista ordenada del documento: una lista con tantos elementos como eventos, cada uno leído como su estado en palabras, su momento, su título y su cuerpo.
- El estado en palabras se lee antes del momento y no se dibuja en ningún sitio. Los marcadores y el conector son decorativos y están ocultos.
- Los tres estados son tres formas, no tres colores, y lo siguen siendo con colores forzados.
- Donde hay exactamente un evento en curso, el script del paquete lo marca como el elemento actual de la lista.
- Un momento con
datetimees el propio elemento time del documento. - El texto crece con los ajustes de quien lee y salta de línea. Nada se corta, se contrae ni se pagina.
- Escribe
role="list"en la lista, y dale nombre con un encabezado que la preceda o conaria-label. - Da
data-status-labelcon cada estado, salvo que el propio texto del evento ya lo diga. - En las versiones actuales de los tres motores de navegador, las palabras llegan a un lector de pantalla a través de la hoja de estilos. Para un navegador más antiguo que se use sin el script del paquete, escríbelas tú como
<span class="tanrei-timeline-status">Completado, </span>al principio del elemento de lista, en lugar dedata-status-label. - Anuncia en una región activa (live region) propia un evento que se añade mientras una persona mira: la línea de tiempo no lo hace.