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
elbow✓0 (or omitted) = sharp corner. Any positive value rounds it, clamped to half the shorter adjacent segment.
straight—Direct line between points, no rounding possible.
smooth—Catmull-Rom-derived bezier. Soft ceiling of 12 points (see getMaxPointsForCurve).
arc✓Omitted 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