Skip to main content
Before data arrives — or when a feed runs dry — the chart shows a placeholder instead of a blank plot. These props control those states and the text the chart renders.
Live example: app/demo/states-and-formatting.tsx in the example app.

Loading and empty placeholders, plus custom value/time formatters

Loading

While you wait for data, pass loading to render a breathing-line placeholder.
If an already-live dataset is cleared for a replacement request, the chart switches to its loading or empty shell immediately — it never visibly morphs the now-stale line flat over the placeholder. When replacement data arrives, the usual grow-in runs; tune that direction with transitions.reveal. The Replace data control in the example app shows the full handoff with a deliberately slow grow-in.

Styling the loading shell

loading also takes a LoadingConfig object to restyle the shell — the squiggle and the skeleton Y-axis placeholders. Every field is optional:
Pass true for the defaults, the object to restyle, and false (or omit) for “not loading” — so loading={!ready && cfg} toggles the styled shell as data arrives. Set axisLabels: false to drop the skeleton Y-axis placeholders and show only the breathing squiggle. amplitude and speed also flow into the brief reveal morph, so the squiggle keeps its wave as it melts into the line. The shell keeps the whole config while it fades out, after loading has turned off. The same config works on LiveChartSeries. The loading→live reveal duration itself is controlled by the transitions.reveal prop.

Freezing the wave

The squiggle animates for as long as the shell shows. A load that keeps failing and retrying, or a chart left empty, can show it for minutes, redrawing it every frame. freezeAfterMs freezes the squiggle once it has animated that long each time the shell appears; its frame callback stops, and it moves again when the shell next appears:
  • Time is counted in frames drawn, at most 34 ms each, so time the app spends in the background, or while LiveChart’s isFrameLoopActive is false, doesn’t use it up.
  • Loading and the empty state that follows it share one budget while the shell stays up. It starts over when the shell appears again after data has shown, also when the data is cleared mid-reveal.
  • The reveal always animates (transitions.reveal bounds it). A frozen squiggle picks the wave up at the current phase as the reveal starts (its shape changes in one frame), so the shell and the morph show one wave.
  • The empty shell takes the limit from the last loading config, like the rest of the look; a chart that has never been loading has no limit.
  • 0 or less freezes the squiggle from the start. Omit it (the default) for no limit; Infinity and NaN mean no limit too.
  • It freezes only the squiggle. The chart’s own frame loop is unaffected; with autoSleep, a loading or empty chart stays awake.

Empty state

When there are no samples and loading is false, the chart shows an empty shell with a label. A single line point or committed candle is valid data and renders normally. Customize the empty label with emptyText. A chart that has been loading keeps that loading config’s look (color, stroke, wave, placeholders, freezeAfterMs) on its empty shell; one that never loaded uses the defaults, with no freeze limit.

Formatting values & time

formatValue and formatTime control the text on axes, the badge, and tooltips. They run on the UI thread, so they must be worklet-safe — mark them with the "worklet" directive and keep them pure (no JS-thread closures). Y-axis calls also provide an optional tickStep in source units. Use it to choose enough precision for nearby compact labels; badges, tooltips and layout samples omit it. For example, this preserves $7.672M / $7.67M / $7.668M for ticks 2,000 units apart, while the ordinary value label remains $7.67M:
The library also exports worklet-safe formatValue / formatTime helpers (adaptive K / M suffixes and HH:MM:SS) you can pass directly or call from your own formatters.