Options Reference

These types are defined once in @trailvine/core and used identically by both @trailvine/react's <Timeline /> and @trailvine/vanilla's renderTimelineSVG/mountTimeline. This page is the single source of truth for what each field does — the React and Vanilla pages mostly just link back here.

TrailvineOptions

The top-level shape both bindings accept.

interface TrailvineOptions<T = {}> {
  points: ExtendedTimelinePoint<T>[];
  layout: LayoutOptions;
  path: PathOptions;
  wrap?: WrapOptions;
  mobileBehavior?: MobileBehavior;
}

Points

interface TimelinePoint<T = {}> {
  date: string;
  title: string;
  subtitle?: string;
  current?: boolean;
  ariaLabel?: string;
}
FieldTypeNotes
datestringJust a label — never parsed as an actual date. Duplicate values across points are fine.
titlestringWrapped per wrap options if provided; otherwise rendered as-is.
subtitlestring?Optional second line — e.g. "Infosys" / "Product Engineer, 5 years".
currentboolean?Marks a point for visual emphasis (a larger dot by default).
ariaLabelstring?Overrides the auto-generated "{date}: {title}" accessibility label.

The generic T lets you attach arbitrary extra fields (a link, an id, an icon) that pass through untouched — the default (no T supplied) stays strictly limited to the fields above.

layout — LayoutOptions

interface LayoutOptions {
  width: number;
  marginX: number;
  bands: number[];
  orientation?: 'horizontal' | 'vertical'; // default: 'horizontal'
}
FieldNotes
widthTotal length along the primary (spread) axis.
marginXMargin at each end of that axis before the first/last point.
bands Y-values (or X-values in 'vertical' mode) cycled through via index % bands.length. Length 2 gives the classic alternating high/low rhythm; length N gives fully non-uniform heights — same mechanism either way, no separate "mode" flag. Use generateBands() if you want evenly-spaced values without hand-picking each one.
orientationSame underlying math, rotated axes. 'vertical' is also what mobileBehavior: 'vertical' switches into automatically on narrow viewports.

path — PathOptions

A discriminated union on curveType — fields like radius only type-check for the curve types where they're actually meaningful.

type PathOptions =
  | { curveType: 'elbow'; radius?: number; maxPoints?: number; asSegments?: boolean }
  | { curveType: 'straight'; maxPoints?: number; asSegments?: boolean }
  | { curveType: 'smooth'; maxPoints?: number; asSegments?: boolean }
  | { curveType: 'arc'; radius?: number; maxPoints?: number; asSegments?: boolean };
curveTyperadiusNotes
elbow0 (or omitted) = sharp corner. Any positive value rounds it, clamped to half the shorter adjacent segment.
straightDirect line between points, no rounding possible.
smoothCatmull-Rom-derived bezier. Soft ceiling of 12 points (see getMaxPointsForCurve).
arcOmitted defaults to half the chord distance (a full semicircle). Larger values flatten the bulge. Soft ceiling of 12 points.

asSegments: true returns string[] (one path per point-to-point segment) instead of one combined string — useful for per-segment styling like dashed-vs-solid, or highlighting up to a hovered point.

wrap — WrapOptions

interface WrapOptions {
  maxChars: number;
  maxLines?: number;
  ellipsis?: boolean;   // default: true when maxLines is set
  measureFn?: (text: string) => number;
}
FieldNotes
maxCharsGreedy word-wrap width. Must be greater than 0.
maxLinesCaps the line count; extra content is cut and the last line gets an ellipsis (unless disabled). Omit for unlimited wrapping.
ellipsisSet false to cut the last line cleanly without adding .
measureFnSubstitutes real DOM text measurement (e.g. getComputedTextLength) for the default character-count heuristic. Only useful client-side — the default is SSR-safe with no DOM at all.

Omitting wrap entirely means titles are never wrapped or truncated — every word always renders somewhere, just potentially on one long line.

mobileBehavior

ValueBehavior
'list' (default)Swaps to a plain vertical list below a breakpoint — pure CSS, no JS required, works during SSR.
'vertical'Switches orientation to 'vertical' below the breakpoint. Needs real viewport access, so only <Timeline /> and mountTimeline support it — renderTimelineSVG alone can't react to resizing.
'none'No responsive behavior at all.

Next steps