Yugen UI

Sparkline & StatTile

Sometimes the answer isn't a chart: StatTile leads with the number, plus a delta and a small trend sparkline.

Sparkline is an inline trend line without axes: gray as background, with the current point in an accent color. StatTile has a label, a value (sans semibold, proportional figures, not tabular), a signed delta with an icon and text (success/danger color based on goodDirection) and an optional sparkline. Use only one hero number per screen.
Yugen Labs · experimentalThis component is outside SemVer: its API can change in a minor release, and What's new says so. Versioning policy
Monthly revenue
$1.28M
Increase+12.4%vs last month

Import

Install from npm, copy the source into your project with @yugen-ui/cli or the shadcn CLI, or import directly when working in this repo.

TSX
// npm install yugen-uiimport { Sparkline, StatTile } from "yugen-ui";

Variants

Each tile is a standalone example: hover to copy, or press Code to see the source.

Revenue grew steadily over 12 months.

Sparkline in a sentence

Inline, as tall as the line of text; the aria-label summarizes the first, last, lowest and highest values automatically.

Variants

variant area; color picks a categorical color slot instead of the background gray.

Churn rate
3.1%
Decrease-0.8%vs last month

Down is good

goodDirection="down": a falling churn rate → success color, always with an icon and text.

Active customers
128.5K
Increase+5.2%vs last quarter

Hero number

size="extra-large" (68px, same sans font) for the one number the screen leads with.

Usage

Do
  • Use StatTile when the data is a single current number (+ a trend), instead of a single-bar chart.
  • State the comparison period of the delta (“vs. last month”) and set goodDirection to match its meaning.
  • Keep sparklines to ~12 points, gray as background, with only the current point in an accent color.
Don't
  • Don't use color as the only signal for the delta. Always include an icon and a signed number.
  • Don't put several hero numbers on one screen.
  • Don't use tabular-nums for a large standalone number.

Props

Prop · TypeDefaultDescription
Sparkline.data(number | null)[]Default: —null creates a gap.
Sparkline.width / heightnumber | "auto" / numberDefault: 120 / 32"auto" = follows the parent element (measured with a ResizeObserver); a number measures nothing.
Sparkline.variant"line" | "area"Default: "line"Line, or line + light fill.
Sparkline.color"neutral" | 1–8Default: "neutral"Background gray or a categorical color slot.
Sparkline.highlightLast / labelsboolean / string[]Default: trueDot on the last point; labels for the tooltip.
StatTile.label / valueReactNode / number | stringDefault: —Numeric values abbreviate automatically from 10,000.
StatTile.delta / deltaFormat / deltaLabelnumber / format / ReactNodeDefault: —Signed change (percent by default).
StatTile.goodDirection"up" | "down" | "neutral"Default: "up"Which direction is good.
StatTile.trend / trendLabels(number | null)[] / string[]Default: —Sparkline next to the value.
StatTile.size"medium" | "large" | "extra-large"Default: "medium"28 / 40 / 68px.

Messages

Text built into the component: labels, aria-labels, screen reader announcements.

English by default. Change it with the messages prop of YugenProvider, by the namespace below; messagesVi has the Vietnamese set. See Interface language.

messages.chart

Key · TypeDefault (English)messagesVi
roleDescriptionstring

aria-roledescription của vùng vẽ.

Default (English)"chart"messagesVi"biểu đồ"
heatmapRoleDescriptionstringDefault (English)"heat map"messagesVi"bản đồ nhiệt"
dataTablestring

Nút bật chế độ bảng của ChartContainer.

Default (English)"Data table"messagesVi"Bảng dữ liệu"
totalstring

Dòng tổng (tooltip, bảng) và nhãn giữa vòng DonutChart.

Default (English)"Total"messagesVi"Tổng"
valuestringDefault (English)"Value"messagesVi"Giá trị"
sharestringDefault (English)"Share"messagesVi"Tỉ lệ"
noDatastringDefault (English)"No data"messagesVi"Không có dữ liệu"
timestring

Tiêu đề cột đầu của bảng (khi không truyền indexLabel).

Default (English)"Time"messagesVi"Thời gian"
categorystringDefault (English)"Category"messagesVi"Danh mục"
groupstringDefault (English)"Group"messagesVi"Nhóm"
namestringDefault (English)"Name"messagesVi"Tên"
otherstring

Nhóm gộp (DonutChart vượt maxSlices, ScatterChart nhóm thứ 9+).

Default (English)"Other"messagesVi"Khác"
trendstring

Nút bật đường xu hướng của ScatterChart.

Default (English)"Trend"messagesVi"Xu hướng"
increasestringDefault (English)"Increase"messagesVi"Tăng"
decreasestringDefault (English)"Decrease"messagesVi"Giảm"
noChangestringDefault (English)"No change"messagesVi"Không đổi"
brushstring

ChartBrush: tên cửa sổ thu phóng, dòng "Đang xem … · n/N mốc", nút đặt lại.

Default (English)"Visible range"messagesVi"Vùng xem"
brushRoleDescriptionstringDefault (English)"zoom window"messagesVi"cửa sổ thu phóng"
brushViewingstringDefault (English)"Showing"messagesVi"Đang xem"
brushPoints(shown: number, total: number) => stringDefault (English)(shown, total) => `${shown}/${total} ${total === 1 ? "point" : "points"}`messagesVi(shown, total) => `${shown}/${total} mốc`
brushResetstringDefault (English)"Reset"messagesVi"Đặt lại"
lineSummary(info: { kind: "line" | "area" | "stacked" | "expand"; points: number; /** Mốc đầu / cuối (chỉ có khi points > 0). */ from?: string; to?: string; series: string[]; }) => string

Mô tả truy cập tự sinh (khi không truyền ariaLabel).

Default (English)Function, see messages.tsmessagesViFunction, see messages.ts
barSummary(info: { horizontal: boolean; stacked: boolean; categories: number; series: string[] }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
donutSummary(info: { groups: number; total: string; largest?: { label: string; share: string } }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
scatterSummary(info: { points: number; x: string; y: string; /** Tên đại lượng kích thước (biểu đồ bong bóng). */ size?: string; /** Tên các nhóm (khi có nhiều nhóm). */ groups?: string[]; trends: { group?: string; slope: string; r2: string }[]; }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
heatmapSummary(info: { rows: number; columns: number; min?: string; max?: string; hasEmpty: boolean }) => stringDefault (English)Function, see messages.tsmessagesViFunction, see messages.ts
sparklineSummary(info: { points: number; first: string; last: string; min: string; max: string }) => stringDefault (English)Function, see messages.tsmessagesVi({ points, first, last, min, max }) => `Xu hướng ${points} điểm: từ ${first} đến ${last}, thấp nhất ${min}, cao nhất ${max}`