Spend alert
ProA budget and spend alert card where the threshold is set right on the live spend bar, with forecast, Email, Slack and PagerDuty toggles, a hard stop and a live preview of the Slack message the alert will post.
- Letting a team set a monthly budget and alert threshold for metered spend.
- Showing how close current and forecast spend are to an alert line.
- Choosing where cost alerts go and previewing the Slack message before saving.
- Read-only usage reporting with no settings; use usage-forecast or usage-billing instead.
- Per-seat plans with no metered spend.
- Complex multi-budget policies across many projects; use a table of budgets that opens this card per row.
Installation
Pro source and install commands unlock with a Pro plan.
Usage
Drop SpendAlert into a billing or usage settings page. Pass `spend` and `period` from your usage API (the forecast is projected for you unless you pass `forecast`), set the starting `defaultValue` (budget, threshold, channels, hardStop), and set `destinations` for your email, Slack channel and PagerDuty service. Wire `onSave` and `onSendTest`: each receives the settings and an AbortSignal, and the card handles the loading, saved, error and unsaved-changes states. Without handlers, both actions are simulated and the live region says so. `onChange` reports every edit.
import { SpendAlert } from "@/components/arc/blocks/spend-alert/spend-alert"; export function BillingAlerts({ usage }: { usage: { spend: number } }) { return ( <SpendAlert project="Production" spend={usage.spend} defaultValue={{ budget: 5000, threshold: 80 }} destinations={{ email: "finance@acme.com", slack: "#eng-spend" }} onSave={async (settings, signal) => { const response = await fetch("/api/budget-alerts", { method: "PUT", body: JSON.stringify(settings), signal }); if (!response.ok) throw new Error("Save failed"); }} /> );}SpendAlert
Budget and spend alert settings in one card: a monthly budget, a threshold slider drawn on the live spend bar, Email, Slack and PagerDuty toggles, a hard stop switch, and a live preview of the Slack message the alert posts. Renders the full demo with no props.
titlestring"Spend alerts"Card title.projectstring"Production"Project or workspace the budget applies to. Used in the subtitle and the Slack message.scopestring"Model API usage"What is being metered, shown in the subtitle.spendnumber3412.8Spend so far this period, drawn as the solid fill on the bar.forecastnumber–Projected spend at period end, drawn as the lighter fill. Defaults to a linear projection from spend and period.period{ label: string; short: string; day: number; days: number; resetsOn: string }{ label: "October", short: "Oct", day: 27, days: 31, resetsOn: "Nov 1" }Billing period used for the forecast, the crossing date and the reset copy.currencystring"USD"ISO 4217 currency code for formatting.defaultValuePartial<SpendAlertSettings>{ budget: 5000, threshold: 80, channels: { email: true, slack: true, pagerduty: false }, hardStop: false }Initial settings. Missing fields fall back to the demo defaults.markersnumber[][50, 80, 100]Threshold markers on the bar. The thumb snaps to them within 2% while dragging, and PageUp or PageDown jumps between them.destinationsPartial<Record<"email" | "slack" | "pagerduty", string>>{ email: "finance@acme.com", slack: "#eng-spend", pagerduty: "Platform on-call" }Where each channel delivers. PagerDuty pages only at 100%.appNamestring"Acme Billing"Sender name in the Slack preview.lastSavedstring"Last edited Oct 24 by Maya Chen"Footer copy while nothing has changed.onChange(settings: SpendAlertSettings) => void–Called on every edit.onSave(settings: SpendAlertSettings, signal: AbortSignal) => Promise<void>–Persist the settings. Without it the save is simulated. Reject to show the error state.onSendTest(settings: SpendAlertSettings, signal: AbortSignal) => Promise<void>–Send a test alert to the enabled channels. Without it the send is simulated.classNamestring–Extra class on the card.- Arrow keys
- On the threshold slider, move the alert line by 1%.
- Shift+Arrow keys
- Move the alert line by 10%.
- PageUporPageDown
- Jump to the next or previous marker.
- HomeorEnd
- Set the threshold to 10% or 100%.
- ArrowUporArrowDown
- In the budget field, change the budget by 100 (Shift for 1,000).
- Space
- Toggle a focused channel or the hard stop switch.
- The threshold is a role="slider" labelled "Alert at" with aria-valuetext giving the percent and the amount.
- The budget field is labelled and described by its helper line, which also carries the invalid and over-budget messages with aria-invalid.
- Each channel switch has its own label; the hard stop switch is labelled by its row title.
- Save and test results land in a polite live region, including "Simulated, nothing was sent" when no handler is wired.
- Status is never color alone: every tone pairs an icon with a short label.
- Spend and forecast fills grow in once when the card scrolls into view (720ms ease-out), then follow budget changes in 160ms.
- The thumb follows the pointer 1:1 while dragging and glides 160ms on clicks, marker jumps and keys.
- Status, helper and footer lines swap with a single crossfade in one grid cell, so nothing changes size.
- Switching Slack off crossfades the preview to a placeholder inside the same box. A test send washes the preview once.
- Reduced motion keeps every end state and drops the fill growth and glides.
- Holds from 360px to 580px. Under 440px the gutter tightens, channel destinations move under their names and the footer actions go full width.
- Every line truncates with an ellipsis rather than wrapping, so state changes never change the card height.
- The slider rail is 28px tall for touch and keeps vertical page scroll (touch-action: pan-y).
- Bar fills animate clip-path and the thumb animates left on one element; no layout animation on text.
- One IntersectionObserver runs until the first reveal, then disconnects.
Notes for AI
Give your coding assistant the Markdown reference instead of screenshots.
- Use for usage-based billing settings: AI model spend, cloud cost budgets, API overage alerts.
- Pass spend and period from your usage API; forecast is derived unless you pass your own.
- Wire onSave and onSendTest with the AbortSignal; the card handles loading, success, error and dirty states.
- Keep it as one card in a settings page; do not wrap it in another card.
The full library index for assistants is at /llms.txt.