BudgetControl
StableShows and sets how much time, money and steps a run may use, and what happens at the limit.
Also known as spend limit, cost limit, budget cap
Install with npm install @tattva/ui (setup), or copy the code from the kit in Downloads.
Limits for a trip search
Limits for this run
Time
12 of 30 minutes used
Spend
4.2 of 5 $ usedClose to the limit
Steps
50 of 50 steps usedLimit reached
Spend: Close to the limit. Steps: Limit reached
<BudgetControl
limits={[
{ id: "time", label: "Time", used: 12, cap: 30, unit: "minutes" },
{ id: "spend", label: "Spend", used: 4.2, cap: 5, unit: "$" },
{ id: "steps", label: "Steps", used: 50, cap: 50, unit: "steps" },
]}
onCapChange={(id, cap) => save(id, cap)}
/>Change a number and the bar updates. Spend is close to its limit and steps have reached theirs.
When to use it
Puts the limits of a run where people can see and change them: time, spend and steps. One choice sets what happens at a limit, so a run never quietly goes past it.
Made of: Heading · Limit row: name, number box with unit · Progress bar · Used of cap text and near-limit note · When a limit is reached choices · Status text for screen readers
Use it for
- Before or during a long run, to set how much time, money or steps it may use.
- Showing how close a run is to each limit.
- Choosing whether a run stops, stops and asks, or asks for more at a limit.
Not for
- Usage of a plan or account over time: use UsageMeter.
- How full the conversation's memory is: use ContextMeter.
- A single bar with no settings: use Meter.
Do and avoid
Limits for this run
Time
12 of 30 minutes used
Spend
4 of 10 $ used
Steps
18 of 50 steps used
Limits for this run
Tokens
41000 of 100000 tok used
Iterations
18 of 50 iters used
Do
- Show used and cap in plain numbers next to the bar.
- Say what happens at the limit before it happens.
- Default to Stop and ask me.
- Use the same unit people see on their bill.
Avoid
- Don't use jargon like 'iterations'. Say steps.
- Don't rely on the bar color alone. A note names the state.
- Don't let a cap go below zero.
- Don't continue past a limit without asking, unless the person chose that.
On a phone
- The limit field opens the number keypad on a phone, and on a touch screen it is 44px tall with 16px text so the page does not zoom.
- Each limit stacks its name above the field when the card is narrow.
- The three choices for what happens at a limit are rows that grow to at least 44px tall on touch screens.
Seen in products
- Anthropic advises stopping conditions such as a maximum number of iterations, to keep control of an agent.
- Shape of AI lists cost estimates among the ways people govern an agent (snippet only).
- Claude Code shows a notice when safety-check requests may be billed.
Properties
| Prop | Type | Default | Description |
|---|---|---|---|
| limitsrequired | BudgetLimit[] | none | Each limit: id, label, used, cap, unit. |
| onCapChange | (id: string, cap: number) => void | none | Called with a valid, non-negative number when the person edits a cap. |
| limitAction | "stop-and-ask" | "stop" | "ask-for-more" | none | What happens at a limit (controlled). |
| defaultLimitAction | LimitAction | "stop-and-ask" | Starting choice when uncontrolled. |
| onLimitActionChange | (action: LimitAction) => void | none | Called when the choice changes. |
| warnAt | number | 0.8 | Fraction of a cap at which a limit counts as close. |
| labels | BudgetControlLabels | none | Replace the heading, choice names, notes and the number box name. |
| headingLevel | 2 | 3 | 4 | 5 | 6 | 3 | Level of the part's own heading, so it fits the page outline. |
| className | string | none | Extra classes on the section. |
"Show code under the preview gives the code for the example on the stage."
In Figma
In Figma, one BudgetControl switches all of this from its properties panel, across 3 variants. Each property sets the React prop beside it, so design and code use the same names.
| Figma property | React | Values |
|---|---|---|
| Limit action | limitAction | Stop-and-ask, Stop, Ask-for-more |
States
States this part has beyond its default look. Build each one your screen can reach. States set by a property are in the Code tab.
- near limit
- When used reaches warnAt of the cap, the bar changes colour and a Close to the limit note appears.
- limit reached
- When used reaches the cap, the note reads Limit reached.
- editing a cap
- Typing a valid number in a limit's box updates it and calls onCapChange.
- focus
- The cap boxes and the radio options show a focus ring on keyboard focus.
Tokens
Change one of these and every part that uses it follows.
--attention--border--surface-sunken--radius-field--radius-card
Built in
- Each bar has a name and a spoken value, such as "12 of 30 minutes used".
- Each number box has a name, such as "Time limit", and shows its unit.
- Limits that are close or reached are announced, and shown with an icon and words.
- The choices for a reached limit are radio buttons that work with the arrow keys.
What you need to do
- Show your own message if a number is not allowed. The box accepts any number from zero up and shows no error.
- Set headingLevel so the heading fits your page outline. It is 3 unless you change it.
Built toward WCAG 2.2 AA and checked automatically; no independent audit yet. Read the accessibility guide