Bloomberg-y "terminal grid" KPI panel — mono numbers, status tags, sparklines, ▲▼ deltas. The header strip is a tab control: each tab swaps in a separate pane with its own tile set and grid layout (different tile counts allowed). Hover any tile for the detail breakdown.
Key Performance Indicators
- Current
- 88.6%
- Previous
- 84.2%
- Δ absolute
- +4.4pp
- Δ percent
- ▲ 5.2%
- Target
- 90.0%
- Current
- $835K
- Previous
- $752K
- Δ absolute
- +$83K
- Δ percent
- ▲ 11.0%
- Target
- $900K
- Current
- 22.9°C
- Previous
- 24.5°C
- Δ absolute
- −1.6°C
- Δ percent
- ▼ 6.5%
- Target
- ≤ 23°C
- Current
- 81.6%
- Previous
- 71.0%
- Δ absolute
- +10.6pp
- Δ percent
- ▲ 14.9%
- Target
- ≤ 75%
- Current
- 0.24%
- Previous
- 0.41%
- Δ absolute
- −0.17pp
- Δ percent
- ▼ 41.0%
- Target
- ≤ 0.50%
- Current
- ¥11.6M
- Previous
- ¥11.2M
- Δ absolute
- +0.39M
- Δ percent
- ▲ 3.5%
- Target
- ¥13.0M
- Current
- $835K
- Previous
- $752K
- Δ absolute
- +$83K
- Δ percent
- ▲ 11.0%
- Target
- $900K
- Current
- ¥11.6M
- Previous
- ¥11.2M
- Δ absolute
- +0.39M
- Δ percent
- ▲ 3.5%
- Target
- ¥13.0M
- Current
- 88.6%
- Previous
- 84.2%
- Δ absolute
- +4.4pp
- Δ percent
- ▲ 5.2%
- Target
- 90.0%
- Current
- 22.9°C
- Previous
- 24.5°C
- Δ absolute
- −1.6°C
- Δ percent
- ▼ 6.5%
- Target
- ≤ 23°C
- Current
- 81.6%
- Previous
- 71.0%
- Δ absolute
- +10.6pp
- Δ percent
- ▲ 14.9%
- Target
- ≤ 75%
- Current
- 0.24%
- Previous
- 0.41%
- Δ absolute
- −0.17pp
- Δ percent
- ▼ 41.0%
- Target
- ≤ 0.50%
1×3 · .pa-col-1-3 columns
Each tile in its own .pa-col-1-3 (33% page-grid column) as a standalone mini-card — no shared terminal-grid chrome, no tabs. Tests how a single tile renders at one-third
of the viewport width, the typical "stat strip" placement.
- Current
- 88.6%
- Previous
- 84.2%
- Δ absolute
- +4.4pp
- Δ percent
- ▲ 5.2%
- Target
- 90.0%
- Current
- $835K
- Previous
- $752K
- Δ absolute
- +$83K
- Δ percent
- ▲ 11.0%
- Target
- $900K
- Current
- ¥11.6M
- Previous
- ¥11.2M
- Δ absolute
- +0.39M
- Δ percent
- ▲ 3.5%
- Target
- ¥13.0M
2×3 stack · .pa-col-25 + .pa-col-45 (asymmetric, 30% empty)
Two page-grid columns: 25% wide on the left (narrow stress test), 45% wide on the right (mid-width). Each holds three standalone tiles stacked vertically. The remaining 30% of the row is intentionally empty — this is the "what does my KPI look like in a sidebar widget" test.
- Current
- 88.6%
- Previous
- 84.2%
- Δ absolute
- +4.4pp
- Δ percent
- ▲ 5.2%
- Target
- 90.0%
- Current
- $835K
- Previous
- $752K
- Δ absolute
- +$83K
- Δ percent
- ▲ 11.0%
- Target
- $900K
- Current
- 22.9°C
- Previous
- 24.5°C
- Δ absolute
- −1.6°C
- Δ percent
- ▼ 6.5%
- Target
- ≤ 23°C
- Current
- 81.6%
- Previous
- 71.0%
- Δ absolute
- +10.6pp
- Δ percent
- ▲ 14.9%
- Target
- ≤ 75%
- Current
- 0.24%
- Previous
- 0.41%
- Δ absolute
- −0.17pp
- Δ percent
- ▼ 41.0%
- Target
- ≤ 0.50%
- Current
- ¥11.6M
- Previous
- ¥11.2M
- Δ absolute
- +0.39M
- Δ percent
- ▲ 3.5%
- Target
- ¥13.0M
Single-pane card · no tabs
The simplest form: KpiTerminal without hasTabs. Children are KpiTerminalTile instances directly; the host wraps them in the canonical pa-kpi-terminal__grid--2col body. Use this when one panel = one view.
Key Performance Indicators
- Current
- 88.6%
- Previous
- 84.2%
- Δ absolute
- +4.4pp
- Δ percent
- ▲ 5.2%
- Target
- 90.0%
- Current
- 0.24%
- Previous
- 0.41%
- Δ absolute
- −0.17pp
- Δ percent
- ▼ 41.0%
- Target
- ≤ 0.50%
Usage Guide
When to use
Bloomberg-style dense KPI panels: per-tile depth (id, status pill, label, focal value, prev row, sparkline) with an optional tab strip on top that swaps in a different pane (different tile set, different grid layout) per tab. Best for trading floor / NOC / operations dashboards where a single panel must carry several distinct views. If you want even-weight grids with less per-tile chrome, pick Sparkline list or Editorial minimal.
Tab strip (optional)
Pass hasTabs on KpiTerminal and supply one or more KpiTerminalPane children — each carries its own id + labelText. The host renders the tab strip
from the registered panes; clicking a tab activates that pane (CSS hides every pane that doesn't have .is-active). Panes are independent: each holds its own __grid--2col and its
own tile count. Section 1 above demonstrates three tabs with 6 / 2 / 4 tiles respectively — the :nth-child border suppressors in core SCSS handle the last-row/last-column edges
regardless of row count.
Bind the active id externally with bind:view. The first registered pane becomes active
by default.
Single-pane card (no tabs)
Without hasTabs, KpiTerminal wraps its tile children in a single pa-kpi-terminal__grid--2col. This is the simplest form — section 4 above. Use this when
one panel = one view.
No wrapper at all
For layout tests / sidebar widgets where you want a single tile in a page-grid column with no
surrounding terminal chrome, render KpiTerminalTile isStandalone directly inside a Grid + Column — no KpiTerminal needed. Sections 2 & 3 above
demonstrate this. The isStandalone modifier adds the full border + card background +
bottom margin that the grid-bookkeeping borders normally provide.
Status pills (different axis from sentiment)
Three pill styles for tile-level status: WARN (filled orange — needs attention), GOOD (text-only — passing, no chrome by design), NEUTRAL (filled grey —
informational). Filled-vs-text is a deliberate hierarchy: filled for "act on this", text-only for
"this is fine, just confirming".
The pill is on a different axis from the 5-step sentiment scale
(very-positive / positive / neutral / negative / very-negative) used on valueVariant and deltaVariant. Sentiment is direction of change (ordinal — "how positive or negative is the movement"). The pill is action urgency (categorical — "does the operator need to do something"). They coexist
intentionally.
Custom chart libraries
The chart snippet is library-agnostic — drop in inline SVG (the default sparkline
pattern), <canvas> + Chart.js / D3 / ECharts, or any other renderer. The pa-kpi-tile__spark class still carries the tile's sentiment color via the variant modifier so currentColor-driven strokes / fills track the sentiment
scale + theme without per-tile overrides.
Sparkline trailing dot
SVG preserveAspectRatio="none" stretches a <circle> into an oval, so
the kpiSparklineDots action converts each circle to an HTML <span> inside a .pa-kpi-spark-wrap on mount. The dot is sized in CSS pixels so it stays a true
circle regardless of chart aspect ratio.
Hover detail popover
Cursor-anchored via Floating UI. The popover is appended to <body> on mount to
escape ancestor overflow: hidden; pointer-events: none so the cursor passes
through. Set detailTitleText to enable the auto-generated rows; override with detailRows (typed list) or the detail snippet (fully-custom markup).
Component Reference
KpiTerminal props
titleText— card title in the header.isLive— show the LIVE pill with animated green dot.footerText— footer caption (plain string). Override via thefootersnippet.hasTabs— switch to tabs+panes mode. Children must beKpiTerminalPaneinstances.view— currently active pane id (bindable). Default: first registered pane's id.
KpiTerminalPane props
id— unique pane id. Used fordata-taband visibility matching.labelText— tab button text shown in the parent's tab strip.tabClass— optional extra class for the tab button (not the pane element).class— optional extra class for the pane element.
KpiTerminalTile props
variant— sparkline + dot trend colour (up-strong/up/flat/down/down-strong).isStandalone— full border + card bg + bottom margin (use when tile lives in a page-gridColumnoutside any terminal grid / pane).idText— small ID label in the head row (e.g. "KPI.01 · 30d").statusText+statusVariant— status pill (good/warn/neutral).labelText— uppercase mono metric label.valueText/valueUnit/valuePrefix/valueVariant— focal value cell + sentiment colour modifier.previousValueText— bare previous value (e.g."84.2%"); tile rendersprev <value>in the bottom row; popover uses the bare value.deltaText+deltaVariant— Δ% in the bottom row + sentiment.detailTitleText— popover title (setting this enables the auto-generated popover).targetText— "Target" row in the auto-generated popover.deltaAbsoluteText+deltaAbsoluteVariant— "Δ absolute" row + sentiment override (defaults to sentiment derived fromdeltaVariant).detailRows— typed-list override for the popover body.chart— sparkline snippet (SVG, canvas, etc.).head/label/value/previousValue/detail— snippet overrides for the respective cells.