Xzero UI
Pro library

Spend alertPro

A 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.

$ pnpm dlx shadcn@4.23.0 add @xzero-ui-pro/spend-alert
Live · keyboard ready

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.

When to use

When not to use

Installation

Register both Xzero UI namespaces in your project's components.json:

{
  "registries": {
    "@xzero-ui": "https://mcp.xzero.co.uk/r/{name}.json",
    "@xzero-ui-pro": "https://mcp.xzero.co.uk/r/pro/{name}.json"
  }
}
npx shadcn@4.23.0 add @xzero-ui-pro/spend-alert

Install xzero-foundation once, and import @/components/xzero/foundation.css in your app root. No Xzero token is used by this snapshot. For sample portraits, photos, fonts, or logos, download https://mcp.xzero.co.uk/install-assets.mjs and run node xzero-install-assets.mjs <receiving-project>.

Usage

import { SpendAlert } from "@/components/xzero/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");
      }}
    />
  );
}

API reference

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.

PropTypeDefaultDescription
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.

Keyboard interactions

KeysAction
Arrow keysOn the threshold slider, move the alert line by 1%.
Shift + Arrow keysMove the alert line by 10%.
PageUp / PageDownJump to the next or previous marker.
Home / EndSet the threshold to 10% or 100%.
ArrowUp / ArrowDownIn the budget field, change the budget by 100 (Shift for 1,000).
SpaceToggle a focused channel or the hard stop switch.

Accessibility

Motion

Responsive behavior

Performance

Notes for AI

Guidance for AI tools

Blocks are complete, self-contained screens with sample data. Replace the sample data and connect the callbacks described above. Follow the declared prop types and do not invent props. Keep keyboard access, reduced motion support, and both light and dark themes intact when adapting it.

Full library index: https://ui.xzero.co.uk/llms.txt

Browse all components