affectUI › Components › Data display
Compact Breakdown
A total split into its parts in one small card – numbers roll, the bar glides and the ranked rows trade places when the period changes.
Part of affectUI Pro. Install: npx shadcn@latest add https://www.affectui.com/r/compact-breakdown.json · Import from @/components/ui/compact-breakdown
When to use
- One number and what it is made of – revenue by channel, usage by feature, tokens by model, tickets by category
- Dashboards where the card sits next to others and a full chart would be too much
- Whenever people switch between periods and should see what moved
When not to use
- Trends over time – a line chart shows those; this card compares the parts of one total
- More than about seven parts – group the small ones into "Other" first
- Several measures and slicing options – use Breakdown Chart
Usage
import { CompactBreakdown } from "@/components/ui/compact-breakdown";
export function RevenueByChannel() {
const [period, setPeriod] = useState("30d");
const { items, delta } = useRevenue(period); // [{ label: "Direct", value: 16900 }, …]
return (
<CompactBreakdown
title="Revenue by channel"
periods={[
{ id: "7d", label: "7d" },
{ id: "30d", label: "30d" },
{ id: "90d", label: "90d" },
]}
period={period}
onPeriodChange={setPeriod}
items={items}
delta={delta}
format={(n) => `$${Math.round(n).toLocaleString("en-US")}`}
totalLabel="Total revenue"
/>
);
}Props
| Name | Type | Default | Description |
|---|---|---|---|
items | BreakdownItem[] | { id?, label, value, color? } – the parts of the shown period; the list ranks them by value. Give an id when labels can change | |
title | string | "Breakdown" | Heading of the card |
periods | { id: string; label: string }[] | Options of the period switch – no switch when left out | |
period | string | Controlled period id | |
defaultPeriod | string | first period | Starting period when uncontrolled |
onPeriodChange | (id: string) => void | Called with the new period – pass the matching items and delta back in | |
delta | number | Change against the previous period in percent (12.4 or -3) – a small green or red pill next to the total | |
format | (value: number) => string | whole numbers with separators | Formats every value – the total, the rows and the hovered part |
totalLabel | string | "Total" | Line under the big number while nothing is hovered |
footer | ReactNode | null | "Largest: <part>" | Replaces the line on the gray tray; null hides it |
className | string | Extra class on the root |
Keyboard
- Tab: Moves to the period switch, then through the rows – a focused row is highlighted like a hovered one
- ← / →: In the period switch: previous or next period (wraps around)
- Home / End: In the period switch: first or last period
Accessibility
- A group named by its title; the period switch is a radiogroup with one tab stop
- The rolling numbers are aria-hidden – screen readers get the final total and the change in one sentence, and every row with its value and share
- Rows can be focused, so the highlight and the part's value are reachable without a mouse
- The bar is decorative: everything it shows is in the list
Responsive
- Fills its container up to 360px; below 250px the share column goes and the values stay
- Touch screens: taller rows and period options
- Dark mode built in: switches when an ancestor (usually <html>) has the class dark or data-theme="dark"
Requirements
- React 19
Related
- Usage Meter – Plan usage and AI credits – a stacked credits meter by category, daily sparkline, limits and a button that speaks up near the limit
- Breakdown Chart – Stacked bar chart with measure, slice and segment pickers, a hover breakdown and a linked table
- KPI Chart – Metric card with a multi-line chart and a tooltip that follows the pointer
Guides
- How to show AI agent costs and token usage – UI patterns for showing what AI agents cost – per run, per step and per agent – plus token usage, context limits and budgets.