Donut
A ring with rounded caps and 2px gaps, the total in the center; ShareBar is the same split in one pill.
- gpt-5$84.2046%
- claude-sonnet-4-5$61.4033%
- gpt-5-mini$22.8012%
- claude-haiku-4-5$14.108%
- gpt-4.1-nano$1.201%
| Slice | Value | Share |
|---|---|---|
| gpt-5 | $84.20 | 45.8% |
| claude-sonnet-4-5 | $61.40 | 33.4% |
| gpt-5-mini | $22.80 | 12.4% |
| claude-haiku-4-5 | $14.10 | 7.7% |
| gpt-4.1-nano | $1.20 | 0.7% |
<Donut aria-label="Spend by model" slices={slices} formatValue={money} totalLabel="Total spend" />import { Donut, ShareBar } from "@logicplanes/kaeso-ui";Props
aria-labelstringThe chart's accessible name ("Requests by model").
emptybooleanShows the empty state (
emptyText) in place of the data. By default it shows when every value is 0.emptyTextReactNodeWhat the empty state says. Defaults to "No data for this period" in the provider's language.
errorReactNodeThe data failed to load: the chart keeps its height, says so quietly and offers Try again. Errors are toasts, so the value isn't shown; toast the message where the request fails.
formatValue((v: number) => string) = (v) => formatNumber(v)Formats the total in the center and the values in the legend. Defaults to
formatNumber.loadingbooleanThe data is loading: the chart keeps its height and shows a quiet loading bar.
onRetry(() => void)Called when Try again is pressed after
error; without it, the button doesn't show.size"md" | "sm" | "lg" = mdThe ring's diameter:
sm140px,md160px (default) orlg180px.slicesSlice[]The parts of the whole, each with an
id, alabel, avalueand an optionalcolor. Slices under 2% are grouped as Other when there are two or more.totalReactNodeReplaces the total in the center, which is otherwise the sum of the slices written with
formatValue.totalLabelReactNodeThe word under the total. Defaults to "Total" in the provider's language.