← All proposals

Milestone

Net-new, in two parts, in their own family so "timeline" keeps one meaning (the log).

Net-new componentOpen in Storybook

proposals/Milestone/decisions.md39 lines · View on GitHub

Decisions: Milestone

Append as you go, newest last. Record choices someone could reasonably question later, not every edit.

Its own family, not part of Timeline (2026-10-22)

  • Decision: Milestone and MilestoneList in proposals/Milestone/. It started as TimelineMilestone plus a variant='milestone' on Timeline (so the list had two modes) and was split out the same day. Timeline and Timeline Item are as they were handed off.
  • Why: too many things called timeline; "timeline" now means the log of events and "milestone" the sequence of steps. The first reason for a separate item was anatomy: a card with a heading, a subtitle and a body, against a one-line row with a status icon and time, with almost no props in common. Splitting the list too keeps the ready-for-dev Timeline free of milestone-only props (variant, subtitlePosition). Renaming the log (ActivityLog) was rejected: it touches 13 files, including handoffs.
  • Port impact: two new components. The shared ol/li and spacing code is duplicated in a small list. Docs say "timeline of milestones" so a search for timeline still finds it.

Answers from Erika (2026-10-22)

  • Marker state: one boolean, isActive (not done / current / upcoming): the milestone in focus. Active has the accent fill and a ring and aria-current='step'; the rest are an empty circle in the line's color. An earlier version had three states and a neutral filled dot; both were replaced.

  • Card: whether there is a card belongs to the list (variant: card or flat), and each milestone can override it, so it is not all or nothing. Reaches milestones through a React context. (A cardVariant prop was removed, see below.)

  • Accent: the interactive link color, on the dot only. The subtitle is the default secondary color, not accent.

  • Heading: headingLevel prop (default 3); the title is pds-heading-m.

  • Subtitle, not date: date / dateTime became subtitle (a node), because it cannot always be a date.

  • Subtitle at the start: subtitlePosition='start' on the list puts it left of the line, baseline-aligned with the title, with a gutter (7xl). Below 480px (phone width) it falls back to under the title; it was 768px at first, which hid the layout in a narrow Storybook pane, so it was lowered (2026-10-22). On the list because the gutter belongs to it; the DOM order is the same either way.

  • Dot placement: the dot sits inside the title (hidden from assistive tech), centered on its first line with 1lh, and is pulled onto the line by the card's border and padding and the list's inset.

  • Active ring stays accent (2026-10-22): the grey ring was compared side by side and rejected. The comparison story and the --milestone-active-ring variable are removed.

Default Panel only (2026-10-22)

  • Decision: removed cardVariant from Milestone and MilestoneList (and the CardVariants and MixedCards stories). The card is the Panel with no variant (default), not raised as before. hasCard stays (replaced by variant below).
  • Why: Erika: use the default panel for now, other variants are not needed yet.
  • Port impact: smaller API. A cardVariant pass-through is easy to add back later through the context.

variant: 'card' | 'flat' instead of hasCard (2026-10-22)

  • Decision: hasCard is replaced by variant (card default, flat) on both components; the list sets it and a milestone can override it. The modifier .pds-milestone--card is unchanged.
  • Why: PDS uses string-union variant props for looks, hasCard={false} is a double negative, and other Panel variants can join the union later.
  • Port impact: none beyond the rename; nothing outside this proposal used hasCard.

Open questions

  • The inactive circle and the line are faint (same light grey); darken both through --milestone-list-line-color?
  • Narrow phone widths and long subtitles are not checked. Dark mode: a11y panel run, no violations (2026-10-22).