ObjectStackObjectStack
Custom Front-endUI plugins

Plugin Timeline

Timeline component with vertical, horizontal, and Gantt-style layouts for displaying events and project timelines.

Installation

npm install @object-ui/plugin-timeline

The props an object-timeline node reads on a page are generated from the spec into the component reference; this page covers using the plugin from React.

Usage

Basic Usage

// Import once in your app entry point
import '@object-ui/plugin-timeline'
import type { TimelineSchema } from '@object-ui/types'

// Use in schemas - Vertical Timeline
const schema: TimelineSchema = {
  type: 'timeline',
  variant: 'vertical',
  items: [
    {
      time: '2024-01-15',
      title: 'Project Started',
      description: 'Kickoff meeting',
      variant: 'success'
    }
  ]
}

Features

  • Three Layout Variants: Vertical, horizontal, and Gantt-style layouts
  • Customizable Markers: Color-coded markers with icon support
  • Date Formatting: Multiple date format options
  • Gantt Charts: Project timeline visualization with task bars
  • Time Scales: Hour, day, week, month, quarter, or year scales for Gantt view
  • Lightweight: Pure CSS and React components

Properties

PropertyTypeDefaultDescription
variantstring'vertical'Timeline layout: vertical, horizontal, or gantt
itemsarray[]Array of timeline items
dateFormatstring'short'Date formatting: short, long, or iso
scalestring'month'Gantt axis bucket: hour, day, week, month, quarter, or year
rowLabelstring'Items'Label for Gantt rows
minDatestringautoOverride min date for Gantt (YYYY-MM-DD)
maxDatestringautoOverride max date for Gantt (YYYY-MM-DD)
classNamestring''Additional Tailwind CSS classes

Every key above is declared on the exported TimelineSchema, so an editor completes them and a wrong value is a type error. scale is the canonical axis key and the only one — it is @objectstack/spec's ui/TimelineConfig.json spelling and the one the renderer reads.

timeScale, the pre-spec spelling of scale, is retired (objectui#6355). It is no longer read, and it is no longer authorable: the key is tombstoned on TimelineSchema, so writing it is a type error and a validation failure rather than a chart that quietly falls back to the month default. Rename the key to scale — the accepted values are unchanged.

events, orientation and position are retired (objectui#6170). Nothing ever read them — a timeline authored with events rendered an empty rail — and they are no longer authorable: each is tombstoned on TimelineSchema, so writing one is a type error and a validation failure. Write items instead of events (each entry { time, title, … }; the date goes in time, not date) and variant instead of orientation. position has no replacement: the vertical rail is always drawn on the left.

Object-bound timeline (object-timeline)

object-timeline fetches records from objectName and draws one entry per record, from the fields its timeline config names. An authored node takes its props in the properties bag, where @objectstack/spec's ComponentPropsMap['object-timeline'] row declares them:

{
  "type": "object-timeline",
  "properties": {
    "objectName": "project_task",
    "timeline": { "startDateField": "start_date", "titleField": "name" },
    "navigation": { "mode": "drawer" }
  }
}

Where the entries come from

The first record source present wins: items (authored entries, drawn as written), then data (pre-fetched records), then a bind path, then the query on objectName. Only the query is a fetch, so objectName is optional: a timeline drawn from items, data or a bind path needs none to draw (entry-click navigation still reads it, below), and a node-level dataSource binding can supply the object instead. Records, from data, a bind path or the query, are composed into entries through the field bindings below; authored items are not.

PropWhat the renderer does with it
timelineNames the record fields an entry is drawn from: startDateField (its date), endDateField (the end printed after it), titleField, groupByField (the field whose value heads each group; without it, entries group into date buckets) and colorField (the marker colour: the field's option colour for the value, or the value itself when it is a colour literal). Each outranks the flat key of the same binding. scale sets the gantt axis unit.
mapping{ title, date, description, variant } field names. title and date are read where the timeline block leaves the binding unset, ahead of the flat keys. variant names the field whose value picks the marker colour (the record's own variant field without it); on the vertical rail a colour from colorField outranks it.
descriptionFieldThe field an entry's description is read from (default description); mapping.description outranks it.
limitThe row cap, lowered to $top (default 100). A value that is not a positive integer is ignored with a console warning.
filter / sortLowered to $filter / $orderby on the query, so they do nothing when items or data supply the entries. The rail draws entries composed from records by start date, earliest first, whatever sort says.
dateFormatshort (the default) or long, both locale-formatted, or iso.
rowLabel, minDate, maxDateThe gantt's row-column header and its pinned axis start and end, read only by the gantt branch, which on this block draws authored items. An empty minDate / maxDate is not honoured; a value that is not a date, or a start after the end, refuses the chart with a diagnostic.

Entry-click navigation

navigation is what an entry click opens — the spec's NavigationConfig by reference, ViewNavigationConfig in @object-ui/types, the type ObjectGridSchema.navigation uses: mode (drawer, page, new_window or none) with size, openNewTab and preventNavigation.

MemberOn an entry click
mode: 'drawer', or a block without mode (the spec's drawer default)Opens the entry's record in the drawer
mode: 'new_window', or openNewTab: trueOpens the record page in a new tab; openNewTab outranks every mode except none. On a timeline that names no objectName there is no record page: the tab opens at a slash and the entry's id alone (its _id when it has no id, undefined when it has neither)
mode: 'page'Opens the record page of the timeline's objectName through the record navigator the host publishes (the console publishes one on its custom pages, record pages and list views); under a host that publishes none, such as an embedded renderer, or on a timeline that names no objectName, it opens nothing
preventNavigation: true, or mode: 'none'Opens nothing, whatever else the block says
sizeSets the overlay width (sm … full, or auto for the default)

A click handler from a parent view outranks the whole key.

With the key absent a click opens nothing: unlike the board and the calendar, this renderer supplies no drawer default.

Variants

Marker Variants

Available marker/bar colors:

  • default - Gray
  • success - Green
  • info - Blue
  • warning - Yellow
  • danger - Red
const item = {
  time: '2024-01-15',
  title: 'Important Milestone',
  variant: 'success'  // Green marker
}

Date Formatting

The timeline component supports three date formats:

import type { TimelineSchema } from '@object-ui/types'

const short: TimelineSchema['dateFormat'] = 'short'  // "1/15/2024"
const long: TimelineSchema['dateFormat'] = 'long'    // "January 15, 2024"
const iso: TimelineSchema['dateFormat'] = 'iso'      // "2024-01-15"

A date-only value (2024-01-15) names a calendar day, so every face prints that day in every viewer's time zone, and the object timeline buckets and sorts it as that day. A value with a time part is an instant: short and long print its day in the viewer's zone, and iso prints its UTC day.

Without a groupByField, the object timeline groups entries into date buckets (Earlier, Today, Tomorrow, This week, Next week, Later, No date). "This week" starts on the first day of the week of the user's display locale, the day the calendar's weeks start on: Sunday under en-US, Monday under en-GB or zh-CN.

Time Scales (Gantt)

For Gantt-style timelines, choose the appropriate time scale:

import type { TimelineSchema } from '@object-ui/types'

const shortProject: TimelineSchema['scale'] = 'day'    // short projects
const mediumProject: TimelineSchema['scale'] = 'week'  // medium projects
const longProject: TimelineSchema['scale'] = 'month'   // long projects

A date-only bar date, minDate or maxDate (2024-01-15) names a calendar day, so the axis headers, the bar positions and the bar tooltips all place it on that day in every viewer's time zone. A value with a time part is an instant and sits at its hour in the viewer's day. A plan with no bar dates and no pinned range shows a one-day axis on the viewer's today.

The headers and the bars share one axis. It runs from the start of the unit that holds the first date to the end of the unit that holds the last. Each header is as wide as its unit is long: hour, day and week columns are equal, and a month is as wide as its days. So a bar lines up under the header of the unit it starts in.

Customization

Custom Icons

const item = {
  time: '2024-01-15',
  title: 'Milestone',
  icon: '🎯',  // Any emoji or short text
  variant: 'success'
}

Custom Colors

Use Tailwind CSS classes for additional styling:

import type { TimelineSchema } from '@object-ui/types'

const schema: TimelineSchema = {
  type: 'timeline',
  variant: 'vertical',
  className: 'max-w-4xl mx-auto',
  items: [
    { time: '2024-01-15', title: 'Milestone', variant: 'success' }
  ]
}

TypeScript Support

import type { TimelineSchema } from '@object-ui/types'

const timelineSchema: TimelineSchema = {
  type: 'timeline',
  variant: 'vertical',
  items: [
    {
      time: '2024-01-15',
      title: 'Event',
      description: 'Description',
      variant: 'success'
    }
  ]
}

On this page