Skip to main content

Timeline

Basic Configuration

The Timeline component has been designed to work together with XY Container. The minimal Timeline configuration looks like:

component.tsx
import { VisXYContainer, VisTimeline } from '@unovis/react'

function Component(props) {
const data: TimeDataRecord[] = props.data
const lineDuration = (d: TimeDataRecord) => d.length
const lineRow = (d: TimeDataRecord) => d.type
const x = (d: TimeDataRecord) => d.timestamp

return (
<VisXYContainer data={data}>
<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
/>
</VisXYContainer>
)
}
Loading...

where each record should provide at least the following information:

type TimeDataRecord = {
timestamp: Date; // Position on the X axis. Can be `number` or `Date`
duration: number; // Length of the line in X axis values, i.e. milliseconds if you use `Date`
name: string; // The row it will be displayed in
}

Wire these up via the lineDuration and lineRow accessors (along with x for the timestamp).

note

The legacy type and length properties on the Timeline component are deprecated. Use lineRow and lineDuration instead.

Row Labels

Enable the showRowLabels property to display row types along the vertical axis. You can control the label width with rowLabelWidth (fixed) and rowMaxLabelWidth (maximum) properties.

note

The showLabels, labelWidth, and maxLabelWidth properties are deprecated. Use showRowLabels, rowLabelWidth, and rowMaxLabelWidth instead.

Like other XY components, labeling data along the horizontal axis can be accomplished by adding an Axis component to your container. See following example which displays labeled Timeline alongside a labeled X Axis:

component.tsx
<VisXYContainer data={data}>
<VisAxis type="x" tickFormat={tickFormat}/>
<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
showRowLabels={true}
/>
</VisXYContainer>
Loading...

Note

Since Timeline groups vertical data in an ordinal fashion, adding a Y axis here is not recommended.

Label Text Align

Use the rowLabelTextAlign property to control the horizontal alignment of row labels: TextAlign.Left, TextAlign.Center, or TextAlign.Right (default).

<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
showRowLabels={true}
rowLabelTextAlign="left"
/>
Loading...

Label Width

Set a fixed label width with rowLabelWidth or a maximum width with rowMaxLabelWidth. Labels longer than the specified value will be trimmed.

<VisTimeline
rowLabelWidth={60}
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
showRowLabels={true}
/>
Loading...

Label Trim Mode

When labels exceed the available width, they'll be trimmed. Use the rowLabelTrimMode property to control where the trimming occurs: TrimMode.Start, TrimMode.Middle (default), or TrimMode.End.

<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
showRowLabels={true}
rowLabelWidth={70}
rowLabelTrimMode="end"
/>
Loading...

Label Margin

Use the rowLabelMargin property to set the spacing (in pixels) between the row labels and the timeline content.

You can also provide a [left, right] tuple to control spacing on both sides of the label independently:

  • The first value sets the left margin (space from the container edge or row icon to the label)
  • The second value sets the right margin (space between the label and the timeline content)
rowLabelMargin: [10, 5] // 10px left, 5px right
<VisTimeline
rowLabelMargin={5}
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
showRowLabels={true}
/>
Loading...

Label Style

Use rowLabelStyle to apply custom CSS styles to row labels. It accepts an object with CSS property-value pairs or an accessor function for per-label styling.

rowLabelStyle: { 'font-weight': 'bold', 'fill': '#333' }

Label Formatter

Use rowLabelFormatter to customize the displayed label text. It receives the row key, the row's data items, and the row index.

rowLabelFormatter: (key: string, items: Datum[], i: number) => `${key} (${items.length})`

Icon

Use the rowIcon property to display an icon before each row label. The function receives the row key, items, and index, and should return a TimelineRowIcon object or undefined.

type TimelineRowIcon = {
href: string; // SVG icon href (defined in container's svgDefs)
size: number;
color: string;
}

Row Configuration

Alternating row colors

For easier readability, each row's background color alternates among two colors by default. To display a single background color across all rows, disable the alternatingRowColors property:

<VisTimeline
alternatingRowColors={true}
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
/>
Loading...

Row Height

Use the rowHeight property to adjust the size of each row.

<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
rowHeight={50}
/>
Loading...

Filling empty vertical space

When the timeline container is taller than the combined height of all rows, rowFillEmptySpace (default: true) stretches row layout so the rows use the extra space. Set it to false if you prefer rows to stay compact at the top and leave the remainder of the container empty.

Line Configuration

Line Cap

By default, lines have squared ends. You can give your lines a rounded appearance by setting lineCap property to true.

<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
lineCap={true}
/>
Loading...

Showing empty segments

Set showEmptySegments to true if you want to display lines that are undefined or too small to see.

<VisTimeline
showEmptySegments={true}
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
lineCap={true}
/>
Loading...

Empty segments positioning

When both showEmptySegments and lineCap are set to true, you can control the positioning of small segments using the showEmptySegmentsCorrectPosition property. When set to true (default), small segments will be centered at their actual position. When set to false, small segments will be aligned to the left of their position.

<VisTimeline
showEmptySegmentsCorrectPosition={true}
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
lineCap={true}
showEmptySegments={true}
/>
Loading...

Line Width

You can also change the line thickness with the lineWidth property, which determines how much vertical space each Timeline item occupies.

<VisTimeline
lineWidth={10}
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
rowHeight={50}
/>
Loading...

Line Cursor

Use the lineCursor property to set a custom CSS cursor when hovering over a timeline line.

note

The cursor property is deprecated. Use lineCursor instead.

Line Icons

You can display icons at the start and/or end of each timeline line using SVG symbols defined in the container's svgDefs.

PropertyDescription
lineStartIcon / lineEndIconSVG icon href accessor
lineStartIconColor / lineEndIconColorIcon color accessor
lineStartIconSize / lineEndIconSizeIcon size accessor
lineStartIconArrangement / lineEndIconArrangementIcon positioning relative to the line: Arrangement.Inside (default), Arrangement.Outside, Arrangement.Start, Arrangement.Middle, or Arrangement.End

Arrows

Use the arrows property to draw connecting arrows between timeline lines. Each arrow is defined as a TimelineArrow object:

type TimelineArrow = {
id?: string;
xSource?: number; // X position of arrow start (defaults to source line's end)
xTarget?: number; // X position of arrow end (defaults to target line's start)
xSourceOffsetPx?: number; // Horizontal offset of the source in pixels
xTargetOffsetPx?: number; // Horizontal offset of the target in pixels
lineSourceId: string; // Id of the source line element
lineTargetId: string; // Id of the target line element
lineSourceMarginPx?: number; // Margin between source line and arrow in pixels
lineTargetMarginPx?: number; // Margin between target line and arrow in pixels
arrowHeadLength?: number; // Arrowhead length in pixels (default: 8)
arrowHeadWidth?: number; // Arrowhead width in pixels (default: 6)
}

The lineSourceId and lineTargetId correspond to the values returned by the id accessor on your data items.

component.tsx
function Component(props) {
const data: TimeDataRecord[] = props.data
const arrows = [{ lineSourceId: 'item-0', lineTargetId: 'item-1', xSource: ... }, ...]
const x = (d: TimeDataRecord) => d.timestamp
const id = (d: TimeDataRecord) => d.id
const lineRow = (d: TimeDataRecord) => d.name
const lineDuration = (d: TimeDataRecord) => d.duration

return (
<VisTimeline
x={x}
id={id}
lineRow={lineRow}
lineDuration={lineDuration}
lineCap={true}
rowHeight={35}
showRowLabels={true}
arrows={arrows}
/>
)
}
Loading...

Events

Scrolling

You can provide a callback to the onScroll property, which accepts a function of type:

type onScroll = (n: number) => void

where n is equal to the distance scrolled from the top of the timeline (in pixels).

See the following example, where onScroll updates the xAxis label:

component.tsx
function Component(props) {
const data: TimeDataRecord[] = props.data
const onScroll = (n: number) => setAxisLabel(`${n}px from the top`)
const lineDuration = (d: TimeDataRecord) => d.length
const lineRow = (d: TimeDataRecord) => d.type
const x = (d: TimeDataRecord) => d.timestamp

return (
<VisTimeline
lineDuration={lineDuration}
lineRow={lineRow}
x={x}
onScroll={onScroll}
/>
)
}
Loading...

Custom cursor for hover events

You can set a custom cursor when hovering over a line using the lineCursor property. It'll only be active if you've defined events for [Timeline.selectors.line]:

More Events

import { Timeline } from '@unovis/ts'

const events = {
[Timeline.selectors.background]: {
wheel: () => { ... },
},
[Timeline.selectors.line]: {
click: () => { ... },
}
[Timeline.selectors.label]: {
mouseover: () => { ... }
}
}

CSS Variables

The Timeline component supports additional styling via CSS variables:

All supported CSS variables and their default values
--vis-timeline-row-even-fill-color: #FFFFFF;
--vis-timeline-row-odd-fill-color: #F7FAFC;
--vis-timeline-row-background-opacity: 1;
--vis-timeline-scrollbar-background-color: #E6E9F3;
--vis-timeline-scrollbar-color: #9EA7B8;
--vis-timeline-label-font-size: 12px;
--vis-timeline-label-color: #6C778C;
--vis-timeline-label-user-select: none;
--vis-timeline-label-pointer-events: all;
--vis-timeline-arrow-color: #6C778C;
--vis-timeline-arrow-stroke-width: 1.5;
--vis-timeline-cursor: default;
--vis-timeline-line-color: var(--vis-color-main);
--vis-timeline-line-stroke-color: undefined;
--vis-timeline-line-stroke-width: 0;
--vis-timeline-line-hover-stroke-width: 0;
--vis-timeline-line-hover-stroke-color: #6C778C;
--vis-timeline-row-icon-cursor: default;
--vis-dark-timeline-row-even-fill-color: #292B34;
--vis-dark-timeline-row-odd-fill-color: #333742;
--vis-dark-timeline-scrollbar-background-color: #292B34;
--vis-dark-timeline-scrollbar-color: #6C778C;
--vis-dark-timeline-label-color: #EFF5F8;
--vis-dark-timeline-arrow-color: #EFF5F8;
--vis-dark-timeline-line-hover-stroke-color: #EFF5F8;

Component Props

NameTypeDescription
* required property