Timeline
The Timeline view of a table. Each record is a bar from its start to its end, or a diamond on its one date, inside a week, month, or quarter window. It is read only and has a text list of the same rows in start order.
Launch plan
Tasks from a table, drawn in a one-month window. Today is pinned to 14 Oct 2026 so the demo stays the same. Tab to the list, then use the arrow keys and Enter.
Showing tasks for all teams, by Start date to Due date.
- Brand refreshSep 14 – Dec 4, 2026Runs past window
- Research interviewsSep 21 – Oct 6, 2026Starts before window
- Pricing pageOct 5 – 16, 2026
- Design QAOct 12 – 14, 2026
- Legal reviewEnd before startEnd before startStarts Oct 15, 2026, ends Oct 12, 2026
- Launch dayOct 21, 2026, no end
- Support rotaOct 26 – Nov 20, 2026Ends after window
Open a row, or use its actions.
Usage
Pass window and TimelineChart shows table rows in one week, month, or quarter. Rows with an end are bars, ends included. Rows with only a start are diamonds. A row that ends before it starts is a hollow diamond with an “End before start” chip. Bars that run past the window are cut at its edge with a chevron, and the label says so. A line marks today.
import {
TimelineChart,
TimelineWindowBar,
timelineRange,
timelineToday,
type TimelineZoom,
} from "@tulipfarm/sprout/timeline";
const today = timelineToday();
const [view, setView] = useState<{ zoom: TimelineZoom; from: string }>({ zoom: "month", from: today });
// The same inclusive YYYY-MM-DD range you query with.
const window = timelineRange(view.zoom, view.from);
<TimelineWindowBar {...view} today={today} onChange={setView} />
<TimelineChart
rows={rows}
rowKey="id"
category="title"
start="start_date"
end="due_date"
title="Tasks"
window={window}
today={today}
status={loading ? "loading" : error ? "error" : "ready"}
onRetry={refetch}
undated={{ count: undatedCount, field: "Start date", action: <Button variant="link" size="sm">Show them</Button> }}
notice={<p>Filtered by owner</p>}
onRowOpen={row => openRecord(row.id)}
renderActions={row => <RowActions row={row} />}
/>- Window:
timelineRange(zoom, from, weekStartsOn)returns the inclusivestartandenddays of the week, month, or quarter that holdsfrom.shiftTimelinesteps to the next or previous one. Both work on calendar dates, so the time zone never moves a day. - Values: dates are
YYYY-MM-DD. Timestamps are epoch milliseconds, shown in the reader’s zone or intimeZone. - Window bar:
TimelineWindowBarhas previous, next, and Today buttons, a live title, and a Week, Month, or Quarter toggle. It stays usable while the timeline loads, is empty, or fails. - Slots:
renderLabelandrenderActionsfill each row,undatedcounts rows with no start, andnoticesits above the chart. The chart is read only; nothing can be dragged. - Keyboard: the labels are an ordered list in start order and one tab stop. Up, Down, Home, and End move between rows, Enter calls
onRowOpen, and Tab reaches the focused row’s actions. The SVG is hidden from screen readers because the list says the same in words. - Size: every row is
--sprout-timeline-rowtall (2.75rem), so the list and the bars line up. Under 40rem the label column narrows to 8rem.