Sophic Interface Systems
Components

Chart

Value-over-time charts with a headline figure, change readout, and range control.

Total value

€93,300.00

up €1,800.00 (1.97%)

Usage

import {
  ChartArea,
  ChartCandlestick,
  ChartPanel,
  ChartRangeControl,
  ChartValueDisplay,
  computeAreaRangeStats,
} from "@sophic/portal-ui/components/ui/charts";
import { SpringReveal } from "@sophic/portal-ui/components/ui/spring-reveal";

ChartPanel owns layout only — swap the plot primitive (ChartArea, ChartCandlestick, ChartValuation, …) without changing the frame. Use layout="responsive" to put the range in the header from sm up and in the footer below.

Named motion for settings reveals is on Animations.

Chart types

PrimitiveUse case
ChartAreaArea sparkline — portfolio / instrument price; optional axes + price guide
ChartArea + dialsInstrument detail: volume, dotted refs, expandable ranges, gear settings
ChartCandlestickOHLC candles for the same dials series (settings toggle); same axis style
ChartValuationValue vs contributions with gain/loss bands
ChartBarSigned P&L bars (green/red per period)
ChartStackedBarMulti-series stacked bars — e.g. contributions + growth
ChartLineLine chart with axes and grid

Instrument dials

Canonical instrument / fund price chart (Option B):

  1. Expandable ranges — ChartRangeControl with extraOptions (trailing …)
  2. Gear settings — type (line / candles icons), volume, details panel; open/close with SpringReveal (spring-pop → soft-dismiss). Defaults: Y axis off, details panel hidden; volume + price guide on.
  3. Plot — ChartArea or ChartCandlestick from the same OHLCV points
  4. Details strip — computeAreaRangeStats; four columns when wide, two when narrow (right column end-aligned); show/hide with SpringReveal
  5. Change readout — amount and parenthesized percent on ChangeIndicator (comma decimal on the percent)

Scrub tooltip date

The scrub chip’s date header is owned by formatLabel on ChartArea, ChartCandlestick, and ChartValuation (default: locale date and time). Product charts pass a label that depends on the series bucket from the API — not the range chip alone.

API fieldEndpointFiner than a dayDaily or coarser
Series.resolutionAccount valuation / earnings series1m · 5m · 15m · 30m · 1h1d
Bar intervalInstrument /series/ohlc5min · 1h1d · 1w

Show hours when the bucket is finer than 1d. Date only when the bucket is 1d or coarser (1w). Prefer the live response value; portal keeps period/range → default tables as fallback while data loads (ACCOUNT_SERIES_DEFAULT_RESOLUTION, INSTRUMENT_PRICE_DEFAULT_INTERVAL in the home chart-ranges module).

<ChartArea
  data={series}
  formatLabel={(timestamp) =>
    formatChartBucketTooltipLabel(timestamp, resolution)
  }
/>

Apply the same rule on every product chart unless a surface opts out.

Playground

import { ChartPanel, ChartArea, ChartRangeControl, ChartValueDisplay,} from "@sophic/portal-ui/components/ui/charts";<ChartPanel layout="responsive" label="Total value" plotBackground={true} edgeFade={true} skeletonVariant="area"  range={<ChartRangeControl value="6m" options={...} />}  headline={<ChartValueDisplay currency="EUR" value={92400} />}> <ChartArea data={areaData} /></ChartPanel>

ChartPanel

Card shell with slots for label, headline, range, footer, and the plot. loading swaps the plot for a ChartSkeleton. For range switches, keep the previous series mounted (placeholderData) with a soft opacity pulse and a translucent skeleton blend (refreshing), then ChartArea morphs once the new points arrive.

Prop

Type

Default

Slot props accept ChartPanelSlot — expand a row in the table above to see the full ReactNode union.

ChartArea

Area sparkline with scrub support and a gradient fill clipped under the line. Pass edgeFade when rendering without ChartPanel (the panel applies the fade to the whole plot region by default).

When onScrub is set (or scrubTint is true), scrubbing tints the prefix green/red vs series open, with a dotted vertical cursor tinted to match and no floating Chart Scrub Tooltip — unless priceGuide / axes turn the chip on. Idle fill uses the color prop (neutral by default; pass positive / negative for at-rest tint, e.g. instrument charts). Pass scrubTint={false} to keep a static color tint with no prefix reveal. On coarse pointers the date-only chip sits on the vertical crosshair above the high price guide.

Optional style (off by default so existing call sites stay sparklines):

  • xAxis / yAxis — labelled ticks (Y reserves width so labels never clip)
  • priceGuide — muted level lines on the plotted series low/high; corner labels on hover
  • Scrub crosshair — vertical + horizontal arms; vertical tinted +/-; Chart Scrub Tooltip chip when style is on (desktop); touch uses on-plot date only
  • tooltip — force the Chart Scrub Tooltip on/off (defaults on with frame)
  • formatLabel — Chart Scrub Tooltip date (see Scrub tooltip date)
  • showVolume — plot volume as a low subplot when points include it
  • referenceLines — unlabeled dotted levels when priceGuide is off
  • animateData — ease the path when data changes (range switches); default on. Hold the previous series until the fetch completes, then morph toward the new points (same vertex count for the whole animation — no end snap). Snaps under prefers-reduced-motion.
  • richer ChartAreaPoint fields (open / high / low / volume) for domain padding and scrub tooltips
  • computeAreaRangeStats(data) — helper for a compact OHLC strip beside the panel

Prop

Type

Default

ChartCandlestick

OHLC candlesticks for instrument dials. Same point shape as ChartArea (value = close). Optional volume subplot and reference lines.

Scrubbing a candle opens the same tinted mono chip as the line chart, with the date on top and Close / Open / High / Low (and Vol when volume is on). Pass formatLabel for the date header — same under-1d time rule as area charts.

<ChartCandlestick
  data={series}
  showVolume
  referenceLines={[rangeOpen]}
  formatValue={(v) => `$${v.toFixed(2)}`}
/>

Prop

Type

Default

ChartValuation

Value vs contributions with gain/loss bands and an optional dashed contributions baseline.

Optional style (off by default):

  • priceGuide — muted series low/high level lines; corner labels on hover
  • tooltip — tinted date + amount scrub chip with H+V crosshair (defaults on with priceGuide). When showContributions is on, the chip also shows the contributions value.
  • referenceLines — unlabeled dotted levels when priceGuide is off
  • formatLabel / formatAxisValue — scrub chip date and guide labels (see Scrub tooltip date)

Total value

Value
Contributions

Prop

Type

Default

ChartBar

Signed period P&L bars — green when positive, red when negative.

Playground

import { ChartPanel, ChartBar, ChartRangeControl, ChartValueDisplay,} from "@sophic/portal-ui/components/ui/charts";<ChartPanel layout="responsive" label="Earnings" plotBackground={false} edgeFade={false} skeletonVariant="bar"  range={<ChartRangeControl value="6m" options={...} />}  headline={<ChartValueDisplay currency="EUR" value={92400} />}> <ChartBar data={barData} /></ChartPanel>

Prop

Type

Default

ChartStackedBar

Multi-series bars stacked on a shared baseline — e.g. contributions plus growth to total value.

Playground

import { ChartPanel, ChartStackedBar, ChartRangeControl, ChartValueDisplay,} from "@sophic/portal-ui/components/ui/charts";<ChartPanel layout="responsive" label="Total value" plotBackground={false} edgeFade={false} skeletonVariant="stacked-bar"  range={<ChartRangeControl value="6m" options={...} />}  headline={<ChartValueDisplay currency="EUR" value={92400} />}> <ChartStackedBar data={stackedData} series={series} /></ChartPanel>

Prop

Type

Default

ChartLine

Line chart with labelled axes and optional horizontal grid.

Playground

import { ChartPanel, ChartLine, ChartRangeControl, ChartValueDisplay,} from "@sophic/portal-ui/components/ui/charts";<ChartPanel layout="responsive" label="Total value" plotBackground={false} edgeFade={false} skeletonVariant="line"  range={<ChartRangeControl value="6m" options={...} />}  headline={<ChartValueDisplay currency="EUR" value={92400} />}> <ChartLine data={lineData} /></ChartPanel>

Prop

Type

Default

ChartRangeControl

Segmented pill range selector. Pass layout="responsive" when the control sits in a ChartPanel with layout="responsive".

Pass extraOptions to add a trailing … segment that expands the same track with more ranges (height morph, fixed radius when expandable, same sliding pill and padding).

Expandable

<ChartRangeControl
  value={range}
  onValueChange={setRange}
  options={primaryOptions}
  extraOptions={extraOptions}
  layout="stacked"
/>

Prop

Type

Default

ChartValueDisplay

Fiat headline with dimmed currency symbol and decimals. Size ladder (xs → xl) keeps relative sizes; default md. Digits roll on value change by default (animated, Balanced motion) — enter scales up with a 1.1 magnify settle, exit scales down. Pass animated={false} for a static render; respects reduced motion. While scrubbing a chart, pass scrubIndex so roll speed tracks pointer motion and stagger collapses under fast scrub. Pass loading for a same-footprint skeleton so surrounding style does not jump.

xl

€93,300.00

lg

€93,300.00

md

€93,300.00

sm

€93,300.00

xs

€93,300.00

Prop

Type

Default

ChartLegend

Line-swatch legend for valuation charts — solid for value, dashed for contributions.

Value
Contributions

Prop

Type

Default

ChartSkeleton

Loading placeholder for the plot region. Set loading on ChartPanel to render it automatically.

Prop

Type

Default

ChartPlotBackground

Dot grid behind the plot. Rendered by ChartPanel when plotBackground is true (default). No props beyond className.

Changelog

  • 1 October 2026 — Valuation scrub chip includes contributions when that overlay is on. Full notes
  • 24 September 2026 — Price-guide low and high sit on the series (tick + figure above the peak, below the trough). Visible at rest; they fade while the pointer is on the chart. Full notes
  • 8 September 2026 — Panel corners use 16px (--radius-2xl) on product tokens. Expandable range track matches (--chart-range-expandable-radius). Full notes
  • 2 September 2026 — Instrument dials: YTD on the primary row; 3Y and 5Y restored in extra. Full notes
  • 25 August 2026 — Shell styles (range, panel, skeleton, value display, scrub chips) in CSS modules; look unchanged. Full notes
  • 25 August 2026 — Candlestick scrub crosshair sits on the wick; volume aligns under the same bucket. Full notes
  • 11 August 2026 — Touch scrub: sticky scrub index; Chart Scrub Tooltip date on the vertical crosshair (touch only); vertical cursor tinted +/-; idle clear 10s. chartScrubTooltip rename. Full notes
  • 11 August 2026 — ChartArea idle color tint; scrub still reveals origin → active point. Full notes
  • 11 August 2026 — Scrub tooltip date: show time only when the API bucket is under 1d (pass formatLabel from resolution / bar interval). Full notes
  • 3 August 2026 — ChartBar hover soft-dims sibling bars (150ms ease) so the active period stays obvious. Full notes
  • 3 August 2026 — ChartBar all-positive series floors at zero (no padded negative Y tick). Full notes
  • 3 August 2026 — ChartBar scrub chip + axes match the line chart (mono tooltip with bold period label; mono tabular ticks). Bars stay green/red; tooltip is foreground when all-positive, signed tint when negatives exist. Full notes
  • 3 August 2026 — ChartBar stronger zero baseline when any bar is negative (centered on zero, slightly past plot edges). Full notes
  • 3 August 2026 — ChartValueDisplay size ladder (xs–xl); total value uses xl + ChangeIndicator lg, other charts default md (instrument change rows use ChangeIndicator xs). Full notes
  • 3 August 2026 — Sparkline plot margins: more vertical inset (top 16 / bottom 16) between change row and range control. Full notes
  • 3 August 2026 — Instrument dials default Y axis + details off; change readout is amount + parenthesized comma percent on ChangeIndicator. Full notes
  • 3 August 2026 — Total-value delta: percent joins the amount on ChangeIndicator (shared color, comma decimal). Full notes
  • 3 August 2026 — Candles scrub with tinted OHLCV chip (date header + Close / O / H / L) and denser-series scrub optimizations. Full notes
  • 3 August 2026 — Scrub vertical crosshair slightly stronger (opacity / weight) so it stays readable in light and dark. Full notes
  • 3 August 2026 — ChartCandlestick scrub uses the same rAF coalesce + memo path as ChartArea (smoother dense OHLC hover). Full notes
  • 3 August 2026 — Total value uses instrument priceGuide style (low/high guides + corner labels on scrub, tinted date chip); ChartValuation gains priceGuide / tooltip / referenceLines. Full notes
  • 1 August 2026 — Details strip toggles with SpringReveal (same enter / exit as gear settings; already-open skips the enter pop). Full notes
  • 31 July 2026 — Range switches hold the prior series with a soft plot pulse, then ChartArea morphs into the fetched points. Full notes
  • 31 July 2026 — ChartArea path morph on data swap (~350ms; opt out with animateData={false}). Full notes
  • 31 July 2026 — Optional xAxis / yAxis / priceGuide plus tinted scrub chip; instrument gear Axes + Price guide dials. Full notes
  • 31 July 2026 — Dense scrub: clip-reveal tint (no per-point remap), onScrub index arg, ChartValueDisplay scrubIndex for roll velocity. Full notes
  • 30 July 2026 — Responsive ChartPanel footer / mobile range keep the same bottom inset as the header bar (fixes Contributions flush to the card corner). Full notes
  • 30 July 2026 — Instrument dials (candles, expandable ranges, gear settings with line/candles icons, OHLC scrub card). Currency headlines always use glyphs ($, €, …). Full notes
  • 29 July 2026 — Dark ChartPanel restores a readable edge hairline. Full notes
  • 22 July 2026 — Headline tracking tightened; active range is a flat white pill with a 0.5px edge. Full notes
  • 17 July 2026 — Added (ChartPanel, ChartArea, ChartValuation, range control, value display, plot grid). Full notes

On this page