Skip to content

LineChart

A responsive SVG line chart with support for multiple series, axis labels, and custom styling.

Examples

Single series

0102030Cases0246810Days
vue
<LineChart
  :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
  :height="200"
  x-label="Days"
  y-label="Cases"
  tooltip-trigger="hover"
/>

x/y

Pass paired x and y arrays to plot points at specific x positions. y is equivalent to data (both names are accepted), and they both take typed arrays. For multi-series charts, set x and y (or data) on each Series.

0102030Cases01020304050Days (log-ish)
vue
<LineChart
  :x="[0, 1, 2, 5, 10, 20, 50]"
  :y="[0, 2, 5, 12, 22, 30, 38]"
  :height="200"
  x-label="Days"
  y-label="Cases"
  tooltip-trigger="hover"
/>

When x is omitted, y/data values are plotted at indices 0, 1, 2, etc.

Dates

Pass ISO date strings (YYYY-MM-DD) or Date objects as x and the chart auto-detects a date axis: ticks anchor to year / month / week / day / hour boundaries depending on the visible range, and labels format themselves accordingly. Numeric x arrays keep their existing behavior — auto-detection is content-driven and never promotes plain numbers.

10203040% ED visitsFeb 2026Mar 2026
vue
<LineChart
  :x="[
    '2026-01-05',
    '2026-01-12',
    '2026-01-19',
    '2026-01-26',
    '2026-02-02',
    '2026-02-09',
    '2026-02-16',
    '2026-02-23',
    '2026-03-02',
    '2026-03-09',
  ]"
  :y="[4, 9, 18, 32, 41, 38, 27, 18, 11, 6]"
  :height="220"
  y-label="% ED visits"
/>

Override the format via x-tick-format. Presets: "iso", "iso-datetime", "year", "month-year", "month-day", "day", "time", "datetime", "medium". You can also pass an Intl.DateTimeFormatOptions literal, or a function (ms, unit?) => string for full control.

10203040% ED visits2026-01-052026-01-122026-01-192026-01-262026-02-02
vue
<LineChart
  :x="['2026-01-05', '2026-01-12', '2026-01-19', '2026-01-26', '2026-02-02']"
  :y="[4, 9, 18, 32, 41]"
  x-tick-format="iso"
  :height="220"
  y-label="% ED visits"
/>

By default the chart parses bare YYYY-MM-DD (and offset-less YYYY-MM-DDTHH:mm:ss) as UTC and renders tick labels in UTC. Set timezone="local" to interpret offset-less strings in the browser's timezone instead. Strings that include an explicit offset (Z or +05:00) are always parsed exactly as written.

Annotations on a date axis. ChartAnnotation.x is always in the chart's resolved coordinate space — that's epoch-ms when the axis is in date mode. Pass Date.UTC(2026, 0, 15), new Date("2026-01-15").getTime(), or Date.parse("2026-01-15T00:00:00Z"). Passing a small integer like 0 will place the annotation at 1970-01-01 (off-screen).

xLabels on a date axis. When both x: [...date strings] and xLabels are supplied, the date axis wins — xLabels is ignored. Date strings carry their own labeling.

Title

The title prop accepts \n to break across lines. Use titleStyle to override fontSize, lineHeight, color, fontWeight, and align ("left" | "center" | "right", default "left"). Top padding grows automatically for additional lines.

Daily ED visitsInfluenza-like illness, last 11 days0102030Cases0246810Days
vue
<LineChart
  :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
  :height="220"
  :title="'Daily ED visits\nInfluenza-like illness, last 11 days'"
  :title-style="{ fontSize: 16, lineHeight: 20, color: '#0057b7' }"
  x-label="Days"
  y-label="Cases"
/>

Font sizes

Every text element on the chart has its own style prop and default size (in px). The text-styling props (axisLabelStyle, tickLabelStyle, legendStyle) take a LabelStyle{ fontSize?, color?, fontWeight? } — and titleStyle adds lineHeight and align. Unset fields fall back to the defaults below.

Chart partProp / fieldTypeDefault size
TitletitleStyleTitleStyle14
Axis labels (xLabel / yLabel)axisLabelStyleLabelStyle13
Axis tick labels (the numbers on each axis)tickLabelStyleLabelStyle10
Inline legendlegendStyleLabelStyle11
Area section labelareaSection.inlineLabelStyleLabelStyle11
Area section descriptionareaSection.inlineDescriptionStyleLabelStyle11
Annotation textannotation.fontSizenumber13

These are single styles applied to both axes — there's no separate x vs y font size. The same props (except the LineChart-only area-section fields) exist on BarChart, since both compose ChartCommonProps.

Daily ED visitsNo interventionsMasking + distancing0204060Cases02468Days
vue
<LineChart
  :series="[
    {
      data: [0, 12, 28, 45, 60, 55, 40, 25, 12],
      color: '#0057b7',
      legend: 'No interventions',
    },
    {
      data: [0, 8, 18, 30, 40, 35, 25, 14, 6],
      color: '#ef4444',
      legend: 'Masking + distancing',
    },
  ]"
  :height="240"
  title="Daily ED visits"
  x-label="Days"
  y-label="Cases"
  :title-style="{ fontSize: 18 }"
  :axis-label-style="{ fontSize: 15, fontWeight: 700 }"
  :tick-label-style="{ fontSize: 13 }"
  :legend-style="{ fontSize: 14 }"
/>

Multiple series

0204060Incidence02468Weeks
vue
<LineChart
  :series="[
    {
      data: [0, 10, 25, 45, 60, 55, 40, 20, 8],
      color: '#fb7e38',
      strokeWidth: 3,
    },
    {
      x: [0, 1, 3, 4, 6, 7, 8],
      y: [0, 5, 20, 28, 18, 10, 4],
      color: '#0057b7',
      strokeWidth: 3,
    },
  ]"
  :height="200"
  x-label="Weeks"
  y-label="Incidence"
/>

Legend

Set legend on a series to add an entry to the inline legend strip above the plot. When the items don't all fit on one row at the chart's current width, the legend wraps to additional rows and the plot area shrinks to keep the legend clear of the data. Use showInLegend: false to keep a series off the legend (e.g. when its legend string is reused as a CSV column header) and showInTooltip: false to omit it from the hover tooltip.

No interventionsSchool closuresMasking + distancingVaccination onlyVaccination + maskingAll interventions combined0204060Incidence02468Weeks
vue
<LineChart
  :series="[
    { data: scenarioA, color: '#0057b7', legend: 'No interventions' },
    { data: scenarioB, color: '#fb7e38', legend: 'School closures' },
    { data: scenarioC, color: '#ef4444', legend: 'Masking + distancing' },
    { data: scenarioD, color: '#10b981', legend: 'Vaccination only' },
    { data: scenarioE, color: '#6366f1', legend: 'Vaccination + masking' },
    { data: scenarioF, color: '#a855f7', legend: 'All interventions combined' },
  ]"
  :height="240"
  x-label="Weeks"
  y-label="Incidence"
/>

Tooltip

Hover over the chart to see a tooltip with values at each data point. Set tooltip-trigger="hover" to enable the built-in tooltip with crosshair and highlight dots. Use the #tooltip slot for custom content. Pass tooltip-value-format to control how numeric values render (e.g. percentages, currency); it falls back to y-tick-format when omitted.

On touch devices, drag horizontally across the chart to scrub the tooltip between points; a vertical swipe scrolls the page instead of getting captured by the chart.

0204060IncidenceJanFebMarAprMayMonth
vue
<LineChart
  :series="[
    {
      data: [0, 10, 25, 45, 60, 55, 40, 20, 8],
      color: '#fb7e38',
      strokeWidth: 3,
    },
    {
      data: [0, 5, 12, 20, 28, 25, 18, 10, 4],
      color: '#0057b7',
      strokeWidth: 3,
    },
  ]"
  :x-tick-format="(_, i) => months[i]"
  :height="200"
  x-label="Month"
  y-label="Incidence"
  tooltip-trigger="hover"
/>

Custom axis ticks

Control tick placement with x-ticks and y-ticks. Pass a number for a fixed interval (in data units, respecting xMin) or an array of explicit values. Use x-tick-format / y-tick-format to customize labels.

0%50%100%Coverageday 0day 7day 14Time
vue
<LineChart
  :data="coverage"
  :x-ticks="7"
  :y-ticks="[0, 0.5, 1]"
  :y-tick-format="(v) => `${(v * 100).toFixed(0)}%`"
  :x-tick-format="(v) => `day ${v}`"
  :height="220"
  x-label="Time"
  y-label="Coverage"
  x-grid
  y-grid
/>

Logarithmic y-axis

Set y-scale-type="log" to switch the y axis to base-10 log scaling. Useful when data spans several orders of magnitude (e.g. epidemic case counts in early exponential growth). Non-positive values collapse to the axis floor, and yMin <= 0 is ignored.

1101001,000Cases02468Day
vue
<LineChart
  :data="[1, 3, 8, 22, 60, 165, 450, 1230, 3350]"
  y-scale-type="log"
  :height="220"
  x-label="Day"
  y-label="Cases"
  y-grid
/>

Dashed baseline

020406002468
vue
<LineChart
  :series="[
    {
      data: [0, 10, 25, 45, 60, 55, 40, 20, 8],
      color: '#999',
      dashed: true,
      strokeWidth: 2,
    },
    {
      data: [0, 5, 12, 20, 28, 25, 18, 10, 4],
      color: '#2563eb',
      strokeWidth: 2,
    },
  ]"
  :height="200"
/>

Outline

Set outline: true on a series to draw a page-colored stroke behind the line. This is useful when lines overlap, cross dense areas, or sit on a busy background — the outline keeps each series visually distinct.

Override the outline's color with outlineColor (any CSS color; defaults to the page background var(--color-bg-0, #fff)) and its thickness with outlineWidth (extra width added to the line's strokeWidth, split evenly per side; defaults to 4).

020406002468
vue
<LineChart
  :series="[
    {
      data: [0, 10, 25, 45, 60, 55, 40, 20, 8],
      color: '#fb7e38',
      strokeWidth: 3,
      outline: true,
    },
    {
      data: [0, 12, 22, 40, 58, 58, 42, 22, 10],
      color: '#0057b7',
      strokeWidth: 3,
      outline: true,
    },
  ]"
  :height="200"
/>

Many trajectories with low opacity

010203040Incidence010203040Days
vue
<LineChart
  :series="trajectories"
  :height="250"
  :line-opacity="0.15"
  x-label="Days"
  y-label="Incidence"
/>

Blend mode

Set blendMode on a Series to apply a CSS mix-blend-mode to that series' line (and dots, if enabled). Useful when two thick or high-contrast lines overlap — "multiply" darkens the crossing point on light backgrounds, "screen" lightens on dark, "difference" inverts. The white outline, if any, is unaffected.

Strain AStrain B102030Incidence01020Day
vue
<LineChart
  :series="[
    {
      data: strainA,
      color: '#ef4444',
      strokeWidth: 3,
      blendMode: 'multiply',
      legend: 'Strain A',
    },
    {
      data: strainB,
      color: '#3b82f6',
      strokeWidth: 3,
      blendMode: 'multiply',
      legend: 'Strain B',
    },
  ]"
  :height="240"
  x-label="Day"
  y-label="Incidence"
/>

Grid lines

0204060Incidence02468Weeks
vue
<LineChart
  :series="[
    {
      data: [0, 10, 25, 45, 60, 55, 40, 20, 8],
      color: '#fb7e38',
      strokeWidth: 3,
    },
    {
      data: [0, 5, 12, 20, 28, 25, 18, 10, 4],
      color: '#0057b7',
      strokeWidth: 3,
    },
  ]"
  :height="200"
  x-label="Weeks"
  y-label="Incidence"
  x-grid
  y-grid
/>

Dots

0102030Cases0246810Days
vue
<LineChart
  :series="[
    {
      data: [0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2],
      color: '#0057b7',
      strokeWidth: 2,
      dots: true,
      dotRadius: 4,
      dotFill: '#fff',
      dotStroke: '#0057b7',
    },
  ]"
  :height="200"
  x-label="Days"
  y-label="Cases"
/>

Confidence band

Use the areas prop to fill a band between two y-series — useful for confidence intervals or min/max envelopes around a mean line. Each Area takes parallel upper and lower arrays (and an optional x array, just like Series). Set legend on an Area to include the band in the inline legend; use showInLegend: false to hide a legend label without removing the field from shared config. Set blendMode on an Area to apply a CSS mix-blend-mode to its fill so overlapping bands combine their colors (e.g. "multiply") instead of the later one obscuring the earlier.

95% interval0102030Cases0246810Days
vue
<LineChart
  :data="mean"
  :areas="[
    {
      upper: ci95Hi,
      lower: ci95Lo,
      color: '#0057b7',
      opacity: 0.15,
      legend: '95% interval',
    },
  ]"
  :height="220"
  x-label="Days"
  y-label="Cases"
  tooltip-trigger="hover"
/>

Area sections

Highlight a range of a series line by filling the area between the line and the x-axis. Labels are rendered below the chart and automatically stack when they overlap.

No interventionsInterventionsDay 2–7 Rapid growth phase050100150Cumulative count0246810DaysDay 5–9Mitigation period
vue
<LineChart
  :series="[
    {
      data: [0, 2, 5, 12, 25, 45, 70, 100, 130, 155, 170],
      color: '#000',
      strokeWidth: 1,
      legend: 'No interventions',
    },
    {
      data: [0, 0, 0, 2, 8, 20, 40, 65, 90, 110, 120],
      color: '#999',
      strokeWidth: 1,
      dashed: true,
      legend: 'Interventions',
    },
  ]"
  :area-sections="[
    {
      startIndex: 2,
      endIndex: 7,
      color: '#6366f1',
      strokeWidth: 0,
      legend: 'inline',
      label: 'Day 2–7',
      description: 'Rapid growth phase',
    },
    {
      seriesIndex: 0,
      startIndex: 5,
      endIndex: 9,
      color: '#f43f5e',
      label: 'Day 5–9',
      description: 'Mitigation period',
    },
  ]"
  :height="250"
  x-label="Days"
  y-label="Cumulative count"
  tooltip-trigger="hover"
/>

Annotations

Pin callouts to data points with annotations. Each annotation anchors at (x, y) in data coordinates (the same x-space as the chart axis, so it respects xMin and explicit x values), with a pixel offset: { x, y } for the label position. Text supports \n for line breaks. A curved pointer line connects the anchor to the label, and the label gets an outline stroke matching the background so it stays legible over series lines.

0102030Cases0510DaysPeakDay 5Onset
vue
<LineChart
  :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
  :annotations="[
    { x: 5, y: 30, offset: { x: 24, y: -28 }, text: 'Peak\nDay 5' },
    { x: 0, y: 0, offset: { x: 28, y: -22 }, text: 'Onset' },
  ]"
  :chart-padding="{ top: 40, right: 24 }"
  :height="240"
  x-label="Days"
  y-label="Cases"
/>

Use chart-padding to reserve room outside the plot so annotations (or any other overlay) don't clip the data area. It accepts a number (same on all sides) or an object with top, right, bottom, left.

Annotation text supports a small set of inline markers:

  • **bold** — bold
  • _italic_ — italic
  • \n — line break

Markers compose (**_bold italic_**).

0102030Cases0510DaysPeakDay 5
vue
<LineChart
  :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
  :annotations="[
    { x: 5, y: 30, offset: { x: 24, y: -28 }, text: '**Peak**\n_Day 5_' },
  ]"
  :chart-padding="{ top: 40, right: 24 }"
  :height="240"
  x-label="Days"
  y-label="Cases"
/>

Multi-line callouts attach to whichever edge of the text faces the anchor: text above the point connects to its bottom edge, text below connects to its top, and text to the side connects to its near vertical edge — so the pointer never cuts through the lines. The demo below anchors the same two-line label at one point and fans it out in every direction.

246810Cases0246DaysClusterdetectedClusterdetectedClusterdetectedClusterdetectedClusterdetectedClusterdetectedClusterdetectedClusterdetected
vue
<LineChart
  :data="[2, 10, 7, 6, 8, 4, 9]"
  :annotations="[
    { x: 3, y: 6, offset: { x: 0, y: -86 }, text: 'Cluster\ndetected' },
    { x: 3, y: 6, offset: { x: 62, y: -62 }, text: 'Cluster\ndetected' },
    { x: 3, y: 6, offset: { x: 96, y: 0 }, text: 'Cluster\ndetected' },
    { x: 3, y: 6, offset: { x: 62, y: 62 }, text: 'Cluster\ndetected' },
    { x: 3, y: 6, offset: { x: 0, y: 86 }, text: 'Cluster\ndetected' },
    { x: 3, y: 6, offset: { x: -62, y: 62 }, text: 'Cluster\ndetected' },
    { x: 3, y: 6, offset: { x: -96, y: 0 }, text: 'Cluster\ndetected' },
    { x: 3, y: 6, offset: { x: -62, y: -62 }, text: 'Cluster\ndetected' },
  ]"
  :chart-padding="{ top: 70, right: 120, bottom: 50, left: 120 }"
  :height="340"
  x-label="Days"
  y-label="Cases"
/>
ts
interface ChartAnnotation {
  x: number; // anchor in data coords (x-axis)
  y: number; // anchor in data coords (y-axis)
  text: string; // label text; \n produces line breaks
  offset: { x: number; y: number }; // pixel offset from anchor to label
  color?: string; // text / pointer color (default: currentColor)
  fontSize?: number; // default: 13 (matches axis labels)
  fontWeight?: string | number; // default: "normal"
  outlineColor?: string; // background-matched outline (default: var(--color-bg-0, #fff))
  outlineWidth?: number; // default: 3
  align?: "left" | "center" | "right"; // default: derived from offset[0] sign
  lineColor?: string; // connector-line color override (default: color)
  lineWidth?: number; // default: 1
  lineDash?: string | number | readonly number[]; // SVG stroke-dasharray
  // default: "curved"
  // "ruleX" / "ruleY" span the full plot on the named axis;
  // "ruleUp" / "ruleDown" / "ruleFromLeft" / "ruleFromRight" run from an edge to the anchor.
  pointer?:
    | "curved"
    | "straight"
    | "none"
    | "ruleX"
    | "ruleY"
    | "ruleUp"
    | "ruleDown"
    | "ruleFromLeft"
    | "ruleFromRight";
  arrow?: boolean; // triangle marker at the anchor end (default: true)
}

Rules

Set pointer to one of the rule values to replace the curved / straight connector with a straight line through the anchor:

  • "ruleX" — vertical line spanning the plot height at the annotation's x.
  • "ruleY" — horizontal line spanning the plot width at the annotation's y.
  • "ruleUp" — vertical from the bottom edge up to the anchor.
  • "ruleDown" — vertical from the top edge down to the anchor.
  • "ruleFromLeft" — horizontal from the left edge in to the anchor.
  • "ruleFromRight" — horizontal from the right edge in to the anchor.

lineColor, lineWidth, and lineDash style the line. The label is positioned from the anchor as usual via offset.

0102030Cases0510DaysPeakMax
vue
<LineChart
  :data="[0, 4, 8, 15, 22, 30, 28, 20, 12, 5, 2]"
  :annotations="[
    {
      x: 5,
      y: 30,
      offset: { x: 8, y: 14 },
      text: 'Peak',
      pointer: 'ruleX',
      lineDash: '4 3',
    },
    {
      x: 5,
      y: 30,
      offset: { x: -8, y: -6 },
      text: 'Max',
      align: 'right',
      pointer: 'ruleFromLeft',
      lineDash: '4 3',
    },
  ]"
  :chart-padding="{ top: 24, right: 24 }"
  :height="240"
  x-label="Days"
  y-label="Cases"
/>

Chart menu

The chart menu (top-right) leads with Fullscreen and then Save as SVG, Save as PNG, and Download CSV. Fullscreen grows the chart to fill the browser window so the plot has more room; while expanded the menu trigger is replaced by a close (✕) button — click it or press Esc to return to the inline size. Set menu="false" to hide the trigger entirely.

While expanded the chart is teleported to <body> so it reliably covers the viewport even when an ancestor uses transform, filter, contain, or establishes a stacking context. If your app doesn't mount at the document root (e.g. inside a shadow root or a dedicated overlay container), point fullscreenTarget at a CSS selector or element to teleport there instead.

Custom CSV download

By default, the Download CSV menu item exports the chart series as CSV. Use the csv prop to supply your own content (for example, to include original dates, categorical labels, or extra columns that aren't plotted). Use filename to control the download filename (shared by SVG, PNG and CSV).

Pass download-link to also render a plain text link below the chart — set it to true for the default label, or pass a string to customize it. Use download-button instead to render a styled <button> (with the class line-chart-download-button, available for custom CSS) in place of the link.

10203040Cases0123WeekDownload weekly cases (CSV)
vue
<LineChart
  :data="[10, 22, 35, 48]"
  :height="200"
  filename="weekly-cases"
  :csv="`week,cases
2024-W01,10
2024-W02,22
2024-W03,35
2024-W04,48`"
  x-label="Week"
  y-label="Cases"
  download-link="Download weekly cases (CSV)"
/>

csv also accepts a function, which is useful for deferring serialization until the user clicks Download:

vue
<LineChart :data="cases" :csv="() => buildCsv(cases, dates)" />

Accessibility

The chart's <svg> is exposed as a single labeled image so screen readers announce one accessible name instead of wandering through the individual marks. When the chart has a title, the <svg> gets role="img" and an aria-label set to the title. The menu and download controls live outside the <svg>, so they stay reachable regardless.

Set ariaLabel to give screen readers a fuller summary than the visible title (it overrides title for the accessible name only):

vue
<LineChart
  :data="cases"
  title="Daily ED visits"
  aria-label="Daily ED visits over 11 days, rising from 12 to a peak of 48"
/>

Pass role to override the default "img" (e.g. role="figure", or a role of your own).

Props

PropTypeRequiredDefault
widthnumberNo
heightnumberNo
titlestringNo
titleStyleTitleStyleNo
rolestringNo
ariaLabelstringNo
axisLabelStyleLabelStyleNo
tickLabelStyleLabelStyleNo
legendStyleLabelStyleNo
xLabelstringNo
yLabelstringNo
debouncenumberNo
menuboolean | stringNotrue
tooltipDataArrayLike&lt;unknown&gt;No
tooltipTrigger"hover" | "click"No
tooltipClamp"none" | "chart" | "window"No"window"
tooltipValueFormatNumberFormatNo
csvstring | (() =&gt; string)No
filenamestringNo
downloadLinkboolean | stringNo
downloadButtonboolean | stringNo
fullscreenTargetstring | HTMLElementNo
annotationsreadonly ChartAnnotation[]No
chartPaddingChartPaddingNo
yLineChartDataNo
dataLineChartDataNo
xLineChartXInputNo
seriesSeries[]No
areasArea[]No
areaSectionsAreaSection[]No
lineOpacitynumberNo1
yMinnumberNo
yScaleType"linear" | "log"No"linear"
xMinnumberNo
xTicksnumber | number[]No
yTicksnumber | number[]No
xTickFormatNumberFormat | ((value: number, index: number) =&gt; string) | DateFormatNo
timezoneDateTimezoneNo
yTickFormatNumberFormatNo
xLabelsstring[]No
xGridbooleanNo
yGridbooleanNo

Data

data, series[].data, and areas[].upper/lower accept a plain number[] or any standard numeric typed array (Float64Array, Int32Array, etc.). This lets you pass the output of ModelOutput.column() directly — no Array.from(...) copy is needed:

vue
<LineChart :data="outputs.series.column('values')" />
ts
type LineChartData =
  | readonly number[]
  | Float64Array
  | Float32Array
  | Int32Array
  | Uint32Array
  | Int16Array
  | Uint16Array
  | Int8Array
  | Uint8Array
  | Uint8ClampedArray;

Series

ts
interface Series {
  y?: LineChartData; // y-values (preferred)
  data?: LineChartData; // y-values (alternative name; one of y/data must be set)
  x?: LineChartData; // optional parallel x-values
  color?: string;
  dashed?: boolean;
  strokeWidth?: number;
  opacity?: number;
  line?: boolean;
  outline?: boolean; // page-colored stroke drawn behind the line
  outlineColor?: string; // outline stroke color (default: var(--color-bg-0, #fff))
  outlineWidth?: number; // extra width added to strokeWidth (default: 4)
  dots?: boolean;
  dotRadius?: number;
  dotFill?: string;
  dotStroke?: string;
}

Area

ts
interface Area {
  upper: LineChartData;
  lower: LineChartData;
  x?: LineChartData; // optional parallel x-values
  color?: string;
  opacity?: number;
  legend?: string; // inline legend label
  showInLegend?: boolean; // default true when legend is set
  blendMode?: BlendMode; // CSS mix-blend-mode for the fill
}

AreaSection

ts
interface AreaSection {
  seriesIndex?: number; // omit for full-height fill
  startIndex: number;
  endIndex: number;
  color?: string;
  opacity?: number; // default: 0.15
  label?: string;
  description?: string;
  strokeWidth?: number; // default: 2
  dashed?: boolean;
  legend?: "inline" | "below" | false; // default: "below"
}