Cost Breakdown

Spend by model, with token volume beside it. The two routinely disagree — the cheap model handling 90% of calls is often 10% of the bill — and either number alone leads to the wrong optimisation.

src/components/ui/cost-breakdown.tsx

About

From the component's own source, where it was written.

Spend broken down by model, with token volume.

Cost and volume are shown side by side because they routinely disagree: the cheap model handling 90% of calls is often 10% of the bill, and a chart of either number alone leads to the wrong optimisation.

Precision follows magnitude rather than position: under a unit gets four decimals, anything larger gets two. A per-call cost rounded to cents is all zeroes, but an aggregate carried to four is both noise and the widest string the column ever has to hold.

That width matters because the currency prefix is locale-dependent — the default en-GB renders USD as "US$", so the same number is three characters wider than it is under en-US. The column is therefore a minimum width that can grow, never a fixed one that clips.

Install

npx astralyx-ui add cost-breakdown

Usage

import { CostBreakdown } from '@/components/ui/cost-breakdown'

<CostBreakdown rows={rows} period="August" budget={250} />

Composer

Change the props and the source below follows.

SpendAugust 2026US$209.90
  • astralyx-large88%US$184.20

    18,400 calls (6% of volume)12,400,000 in2,100,000 out

  • astralyx-small10%US$21.60

    214,000 calls (65% of volume)88,200,000 in9,600,000 out

  • astralyx-embed2%US$4.10

    96,200 calls (29% of volume)41,000,000 in

BudgetUS$209.90 of US$250.00
Props
tsx
<CostBreakdown rows={rows} period="August 2026" budget={250} />

Examples

Spend

API

Generated from the source, so it cannot fall behind the code. One table per exported component, then hooks, functions and types.

CostBreakdown

Extends Omit<ComponentProps<'div'>, 'children'>.

PropTypeDefaultDescription
titlestring'Spend'—
rowsCostRow[]required{ id, label, cost, inputTokens?, outputTokens?, calls?, color? }. Input and output are kept apart because they are priced differently.
currencystring'USD'—
periodReactNode——
budgetnumber—Adds a budget line and flags an overage.
budgetLabelReactNode'Budget'—
callsLabelReactNode'calls'Follows the call count.
volumeLabel(share: number) => ReactNodeDEFAULT_VOLUME_LABELThat row's share of total calls, given the percentage.
inputTokensLabelReactNode'in'Follows the input-token count.
outputTokensLabelReactNode'out'—
widthmin-w, not w—The currency prefix is locale-dependent — en-GB renders USD as "US$", three characters wider than en-US — so the amount column grows rather than clipping.

Types

CostRow

Spend broken down by model, with token volume.

FieldTypeDescription
idstring—
labelReactNode—
costnumber—
inputTokens?numberInput and output tokens, kept apart — they are priced differently.
outputTokens?number—
calls?number—
color?string—

Behaviour

TopicDetailDescription
precisionby magnitudeUnder a unit gets four decimals, larger amounts two. A per-call cost rounded to cents is all zeroes; an aggregate carried to four is noise, and the widest string the column has to hold.