Skip to content

Charts (line / bar / area / pie / scatter / graph)

components specs/components/charts.kmd

Canonical chart primitives — line / bar / stacked-bar / area / scatter / pie / donut / sparkline / graph (node-edge). Behavior contract; library binding is impl detail. Replaces ad-hoc chart-lib picks in Koder admin tools (Forge metrics, Hub analytics, Talk stats). Modeled after Ant Design G2/G6 + PatternFly + Material 3.

When this spec applies

Primary triggers

All triggers

Specification body

Component — Charts

Status: v0.1.0 — Draft. Behavior contract; library binding (Victory / Recharts / G2 / fl_chart for Flutter) is impl detail chosen per surface.

R1 — Chart-type catalog

TypeUse when
LineContinuous data over time; 1-5 series
BarCategorical comparison; vertical default, horizontal on long labels
Stacked barPart-of-whole over categories
AreaMagnitude over time with emphasis on cumulative value
ScatterCorrelation between two variables; outlier detection
PiePart-of-whole, ≤ 5 slices (otherwise use bar)
DonutPie + central value display
SparklineInline mini-chart in tables / cards; no axes
GraphNodes + edges (topology, dependency, mind-map)

Other types (treemap, sankey, heatmap, candlestick, 3D, geospatial) out of v0 — open separate ticket if a Koder product needs one.

R2 — Color usage

  • Series colors: cycle through Verge accent palette in canonical order (defined in specs/themes/color-roles.kmd — for v0 use --kdr-accent → +30° HCL → +60° → +90° → +120°). NEVER hardcode hex; consume via tokens.
  • Status colors (success / warning / danger) used ONLY when the data itself is status-typed (uptime chart green/yellow/red); otherwise stick to the accent cycle.
  • Color-blind a11y per specs/themes/a11y-modes.kmd (#062):
    • Lines and bars MUST also vary in pattern / stroke style when ≥ 3 series share a chart — color alone is insufficient.

R3 — Axes

  • X-axis labels rotate to 45° when overlap detected (auto), otherwise horizontal.
  • Y-axis: locale-aware number formatting (per specs/content/grammar- and-mechanics.kmd R4 — 1,234.56 en-US vs 1.234,56 pt-BR).
  • Grid lines: subtle (--kdr-border at 50% opacity); never dominate the data.

R4 — Tooltips

On hover (or focus / tap), show a tooltip:

  • Series name (per legend) + data point value
  • For multi-series at the same X position: stacked tooltip listing all series + values
  • Position: above the data point; flips below if no space
  • Dismiss: pointer leave / blur / outside-tap / Esc

R5 — Keyboard navigation

KeyAction
TabEnter the chart (focus moves to first data point)
← / →Navigate adjacent data points within a series
↑ / ↓Switch active series (multi-series charts)
Enter"Drill" — emit a drill event (consumer handles)
EscExit chart focus

R6 — Screen-reader

  • Each chart MUST emit a <table> data-alternate sibling (role="presentation" if visually hidden), so SR users can read the data values without parsing the SVG.
  • Chart container role="img" with aria-label = chart title + brief description (e.g. "Line chart, monthly active users, 6 months").
  • On focused data point: live-region announces "{series}: {value} at {x-label}".

R7 — i18n

  • Axis labels, legend labels, tooltip series names translatable per specs/i18n/contract.kmd.
  • Number formatting per locale (R3).
  • Date formatting on time-axis charts: locale-aware short form (per specs/components/date-picker.kmd R7).

R8 — OUIA

Per specs/testing/ouia-test-hooks.kmd:

  • data-ouia-component-type="Chart" (or LineChart, BarChart, … for type-specific)
  • data-ouia-component-id="<chart-slug>"
  • data-ouia-safe="true" only when data loaded + render complete (no animation in progress).

R9 — Empty / loading / error

  • Empty data: render patterns/empty-state.kmd inside chart container.
  • Loading: components/skeleton.kmd shape mirror (a placeholder grid).
  • Error: error pattern with retry button (when data fetch fails).

Não-escopo

  • Specific library binding (Victory vs Recharts vs G2 vs fl_chart) — consumer choice; spec ratifies behavior contract only.
  • Real-time streaming / WebSocket data updates (separate ticket if pursued).
  • 3D, geospatial, financial candlestick, heatmap, treemap, sankey (case-by-case; open ticket per type when a product needs one).

Requirements (testable)

Requirement: Series color cycling and color-blind redundancy {#req-charts-color-encoding}

Chart series SHALL derive their colors from the Verge accent token cycle in canonical order and SHALL NOT hardcode hex values; when three or more series share a chart, each series SHALL additionally vary in pattern or stroke style so that color is never the sole distinguishing encoding.

Scenario: Series colors come from tokens, not hardcoded hex

  • GIVEN a line chart with three series
  • WHEN the chart renders
  • THEN each series stroke resolves to a Verge accent token (--kdr-accent, then +30° / +60° HCL steps) in canonical order
  • AND no series stroke is a literal hardcoded hex color

Scenario: Three or more series add pattern redundancy

  • GIVEN a bar chart configured with four series
  • WHEN the chart renders
  • THEN each series is drawn with a distinct pattern or stroke style in addition to its color
  • AND two series with adjacent accent hues remain distinguishable when color is removed

Requirement: Hover and focus tooltips {#req-charts-tooltip}

A chart SHALL present a tooltip on hover, focus, or tap that shows the series name and the data-point value, SHALL list all series with their values when multiple series share the same X position, and SHALL dismiss the tooltip on pointer leave, blur, outside-tap, or Esc.

Scenario: Multi-series tooltip lists every series at the X position

  • GIVEN a chart with three series sharing an X coordinate
  • WHEN the pointer hovers that X position
  • THEN the tooltip lists all three series names with their values

Scenario: Esc dismisses the tooltip

  • GIVEN a visible tooltip on a focused data point
  • WHEN the user presses Esc
  • THEN the tooltip is removed from the view

Requirement: Keyboard navigation of data points {#req-charts-keyboard}

A chart SHALL be fully keyboard operable: Tab SHALL move focus to the first data point, Left/Right SHALL navigate adjacent data points within a series, Up/Down SHALL switch the active series on multi-series charts, Enter SHALL emit a drill event, and Esc SHALL exit chart focus.

Scenario: Arrow keys move within and across series

  • GIVEN a multi-series chart with focus on the first data point of series 1
  • WHEN the user presses Right and then Down
  • THEN focus advances to the next data point in series 1
  • AND then moves to the corresponding data point in series 2

Scenario: Enter emits a drill event

  • GIVEN a focused data point
  • WHEN the user presses Enter
  • THEN a drill event is emitted for the consumer to handle

Requirement: Screen-reader accessibility {#req-charts-screenreader}

A chart SHALL expose its data to assistive technology: it SHALL emit a data-alternate <table> sibling readable by screen readers, its container SHALL carry role="img" with an aria-label combining the chart title and a brief description, and a focused data point SHALL be announced via a live region as "{series}: {value} at {x-label}".

Scenario: Chart exposes a data-alternate table and img role

  • GIVEN a line chart of monthly active users over six months
  • WHEN the chart renders
  • THEN the container has role="img" with an aria-label containing the chart title and description
  • AND a sibling <table> carrying the same data values is present in the DOM

Scenario: Focused data point is announced

  • GIVEN a chart with keyboard focus on a data point
  • WHEN focus lands on that point
  • THEN a live region announces "{series}: {value} at {x-label}" for that point

Requirement: OUIA test hooks {#req-charts-ouia}

A chart SHALL expose OUIA hooks: data-ouia-component-type set to Chart (or the type-specific name such as LineChart), data-ouia-component-id set to the chart slug, and data-ouia-safe="true" only once data is loaded and rendering is complete with no animation in progress.

Scenario: Safe flag is false during animation and true once settled

  • GIVEN a chart whose data has loaded and whose entry animation is running
  • WHEN rendering is still animating
  • THEN data-ouia-safe is false
  • AND once the animation completes data-ouia-safe becomes true

Requirement: Empty, loading, and error states {#req-charts-states}

A chart SHALL render the canonical empty-state pattern inside its container when there is no data, SHALL render the skeleton placeholder grid while loading, and SHALL render the error pattern with a retry button when a data fetch fails.

Scenario: Empty data renders the empty-state pattern

  • GIVEN a chart bound to an empty dataset
  • WHEN the chart renders
  • THEN the empty-state pattern is shown inside the chart container
  • AND no data marks (lines, bars, points) are drawn

Scenario: Fetch failure renders an error with retry

  • GIVEN a chart whose data fetch fails
  • WHEN the failure is surfaced
  • THEN the error pattern is shown with a retry button that re-triggers the fetch

References