Sparkline
A tiny, word-sized trend line, area, bar, or occupancy chart, single-tone and axis-free, for inline use or a live time-series.
Live demo
Sparkline draws a single series of numbers as a small, axis-free SVG that reads as a trend at a glance, sized to sit inline in a sentence, a table cell, or beside a Stat. Four shapes: a line, a filled area, a mini bar run, or an occupancy strip that fills each "on" sample of a bool/binary series as a solid block (uptime, presence, connection state) rather than drawing a 0/1 line.
Feed it evenly-spaced values, or switch to points (timestamped samples) for a real time-series: they map onto a sliding window (or an explicit domain), so irregular samples sit at their true position and slide left over real time. Add step to hold each value for an on/off signal. It takes one tone from the theme roster (any semantic role or named hue) and marks the latest point with an end dot. It's interactive: sweeping across it floats a marker and the value at the nearest point, and format makes that readout speak the metric's units (duration as 42s/1.5m, percent as 87%, bytes, or a plain unit). Size it with the --spark-width and --spark-height custom properties; give it a label for an accessible name. Auto-ranged from the data, pinned with min / max, or ranged by kind with bounds: percent locks [0, 100], unit locks [0, 1], and duration caps at a rolling power of two so a latency spike lifts the ceiling instead of squashing the baseline; the per-kind range every consumer of a typed metric would otherwise re-derive by hand. An empty series shows a muted No data label instead of a blank box.
When to use
How this component composes with the rest of the set.
Props
13 props, straight from the manifest.
| Prop | Type | Default | Bindings | Description |
|---|---|---|---|---|
at is epoch ms or a date string) placed on a real time axis instead of even spacing, so irregular samples read at their true position and slide left over time. JS property in html/svelte, JSON attribute or prop in astro. Pair with window or domain; overrides values when set. | ||||
points mode, and ignored when domain is set. | ||||
[start, end] time span (epoch ms or date strings) for the x-axis, instead of the sliding window. JSON attribute or prop. | ||||
occupancy strip that fills each "on" sample of a bool series as a solid block. Pair occupancy with bounds="unit" for a clean 0/1 threshold. | ||||
show-end on the element. | ||||
percent → [0, 100]; unit → [0, 1] (a fraction or bool); duration → [0, rolling power-of-two cap] so a spike lifts the ceiling instead of squashing the baseline. An explicit min/max overrides it. | ||||
duration reads seconds as 42s / 1.5m / 0.3h, percent appends %, bytes steps B/KB/MB/…, unit is a trimmed number. Independent of bounds (range vs. label); unset shows the raw value. | ||||
Appearance
Variants
line
A stroked trend line, the default.
area
The line with a soft fill down to the baseline.
bar
A run of tiny bars, one per value.
occupancy
A filled block per "on" sample of a bool/binary series over a faint track; the on/off reading a step line can't give.
States
hover
Sweeping across the chart floats a guide, a dot at the nearest point, and its value.
Anatomy
The named parts that make up the component, with their selectors. This one renders light DOM, so the selector is the handle.
sparkline
The inline-block root sized by --spark-width / --spark-height, tinted by --spark-color.
line
The trend polyline (or the area's outline), stroked in the tone.
end
The dot marking the most recent value.
occupancy-track
The faint full-width rail behind an occupancy strip that shows the empty (off) slots.
occupancy-block
A filled block for each "on" sample of an occupancy strip, in the tone.
marker
The hover guide, dot, and value tooltip shown while sweeping across the chart.
Tokens & coverage
What the component consumes, checked live against what the algorithm produces.
Live coverage check against the xtyle-default register
(derive(xtyleDefault, { anchors }) →
coverComponent(manifest, register)). Every token this component
consumes must be a key the algorithm produces.
--accent--accent--accent-2--accent-3--accent-4--bg-0--black--blue--border-thin--brown--cyan--danger--elevation-3--fg-0--fg-2--font-sans--gray--green--info--leading-normal--line--line-2--neutral--orange--pink--purple--radius-md--red--space-1--space-2--success--surface-overlay--surface-overlay-border--text-xs--warn--white--yellowAccessibility
Code
Line, area, and bar
The same series as a stroked line, a filled area, and a mini bar run, each in a different tone.
<xtyle-sparkline values="4,6,5,8,7,9,12,10,13" label="Weekly signups"></xtyle-sparkline>
<xtyle-sparkline values="4,6,5,8,7,9,12,10,13" variant="area" tone="success"></xtyle-sparkline>
<xtyle-sparkline values="4,6,5,8,7,9,12,10,13" variant="bar" tone="purple"></xtyle-sparkline><script lang="ts">
import { Sparkline } from "@xtyle/svelte";
const trend = [4, 6, 5, 8, 7, 9, 12, 10, 13];
</script>
<Sparkline values={trend} label="Weekly signups" />
<Sparkline values={trend} variant="area" tone="success" />---
import { Sparkline } from "@xtyle/astro";
const trend = [4, 6, 5, 8, 7, 9, 12, 10, 13];
---
<Sparkline values={trend} label="Weekly signups" />
<Sparkline values={trend} variant="area" tone="success" />Inline in text
Sized down with --spark-width / --spark-height to sit word-height in a sentence.
<p>
Signups this week
<xtyle-sparkline values="4,6,5,8,7,9,12,10,13" tone="accent" style="--spark-width: 5rem; --spark-height: 1.2rem;"></xtyle-sparkline>
up 34%.
</p><p>
Signups this week
<Sparkline values={trend} style="--spark-width: 5rem; --spark-height: 1.2rem;" />
up 34%.
</p><p>
Signups this week
<Sparkline values={trend} style="--spark-width: 5rem; --spark-height: 1.2rem;" />
up 34%.
</p>Time-windowed series
points with timestamps on a sliding window place irregular samples at their true position over real time, so a live signal reads honestly instead of assuming even spacing. Add step for a held on/off series.
<xtyle-sparkline window="300000" variant="area" tone="info" label="Signal, last 5m"></xtyle-sparkline>
<script>
const spark = document.querySelector("xtyle-sparkline");
// irregular samples over real time: { at: epoch ms | ISO string, value }
spark.points = history;
</script><script lang="ts">
import { Sparkline } from "@xtyle/svelte";
// { at: epoch ms | ISO string, value }[]
const history = readSignalHistory();
</script>
<Sparkline points={history} window={300000} variant="area" tone="info" label="Signal, last 5m" />---
import { Sparkline } from "@xtyle/astro";
const history = readSignalHistory(); // { at: epoch ms | ISO string, value }[]
---
<Sparkline points={history} window={300000} variant="area" tone="info" label="Signal, last 5m" />Kind-aware bounds
bounds ranges a typed metric without hand-math: percent pins [0, 100], unit pins [0, 1], and duration caps at a rolling power of two so a spike lifts the ceiling rather than flattening everything else.
<!-- A percent series pins to [0, 100] so 40% reads as 40% of full height -->
<xtyle-sparkline values="38,41,52,49,63,58,71" bounds="percent" tone="info" label="CPU %"></xtyle-sparkline>
<!-- A duration series caps at a rolling power of two, so one spike lifts the ceiling
instead of squashing the baseline -->
<xtyle-sparkline values="120,90,140,110,760,130,150" bounds="duration" tone="warn" label="Latency ms"></xtyle-sparkline><script lang="ts">
import { Sparkline } from "@xtyle/svelte";
</script>
<Sparkline values={cpu} bounds="percent" tone="info" label="CPU %" />
<Sparkline values={latency} bounds="duration" tone="warn" label="Latency ms" />Occupancy strip for a bool series
variant="occupancy" fills each "on" sample as a solid block over a faint track; the uptime/presence/connection reading a 0/1 step line can't give. Pair with bounds="unit".
<!-- A bool/occupancy series: "on" samples read as solid blocks, "off" as gaps -->
<xtyle-sparkline values="1,1,0,1,1,1,0,0,1,1" variant="occupancy" bounds="unit" tone="success" label="Uptime"></xtyle-sparkline><script lang="ts">
import { Sparkline } from "@xtyle/svelte";
// 1 = up, 0 = down
const uptime = [1, 1, 0, 1, 1, 1, 0, 0, 1, 1];
</script>
<Sparkline values={uptime} variant="occupancy" bounds="unit" tone="success" label="Uptime" />Units in the hover readout
format makes the hover value speak the metric's units — a latency series reads 1.5m instead of 90, a load series reads 87%. Independent of bounds, which ranges the y-axis.
<!-- Latency in seconds: the hover reads 1.5m, not 90 -->
<xtyle-sparkline values="42,58,90,73,120,66,54" format="duration" bounds="duration" tone="warn" label="Latency"></xtyle-sparkline>
<!-- Load as a percentage: the hover reads 87% -->
<xtyle-sparkline values="38,41,52,49,87,58,71" format="percent" bounds="percent" tone="info" label="Load"></xtyle-sparkline><script lang="ts">
import { Sparkline } from "@xtyle/svelte";
const latency = [42, 58, 90, 73, 120, 66, 54]; // seconds
const load = [38, 41, 52, 49, 87, 58, 71]; // percent
</script>
<Sparkline values={latency} format="duration" bounds="duration" tone="warn" label="Latency" />
<Sparkline values={load} format="percent" bounds="percent" tone="info" label="Load" />