Xzero UI
Pro library

Budget variancePro

Budget against actual operating spend by department as aligned bullet charts, with favorable and unfavorable variance, a month, quarter and year to date switch that springs every bar, in-place drill-down into budget lines, and a total row.

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

Render <BudgetVariance /> for the demo, or pass departments (lines with budget and actual keyed by period id), periods, defaultPeriod, defaultExpanded and ranges. Department figures and the total are summed from the lines, and onPeriodChange and onDepartmentToggle report changes.

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/budget-variance

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 { BudgetVariance } from "@/components/xzero/blocks/budget-variance/budget-variance";

export function FinanceOverview({ departments }) {
  return (
    <BudgetVariance
      departments={departments}
      defaultPeriod="quarter"
      ranges={[0.9, 1.05]}
      onDepartmentToggle={(id, open) => open && prefetchLines(id)}
    />
  );
}

API reference

BudgetVariance

Budget against actual spend by department as bullet charts on one shared scale, so every budget tick lines up down the table. Each row shows qualitative bands, the actual bar with the overspend drawn in the danger color past the tick, and variance as a signed amount and share colored by whether it is favorable. A month, quarter and year to date switch springs every bar and counts every number to the new window, a total row sums the table, and any department opens in place to show its budget lines.

PropTypeDefaultDescription
departmentsBudgetDepartment[]budgetDepartmentsDepartments with an id, a name, an owner ({ name, avatar? }) and budget lines. Each line has an id, a name, and budget and actual amounts keyed by period id. Department figures and the total are summed from the lines.
periodsBudgetPeriod[]budgetPeriodsReporting windows for the switch, each with an id, a short label, a description shown under the title and a phrase for screen reader sentences ("in the third quarter").
defaultPeriodstring–Id of the window shown first. Defaults to the first period.
defaultExpandedstring | null"engineering"Id of the department open on first render. Pass null to start with every department closed.
ranges[number, number][0.9, 1.1]Qualitative band edges as shares of budget. Spend between them is within tolerance; the bands step darker past the upper edge.
onPlanThresholdnumber0.005Variance smaller than this share of budget reads as on plan and stays neutral.
currencystring"$"Symbol placed before every amount. Amounts shorten to k and M.
titlestring"Budget vs actual"Heading of the block.
descriptionstring–Replaces the period description under the title.
onPeriodChange(periodId: string) => void–Called when the reporting window changes.
onDepartmentToggle(departmentId: string, open: boolean) => void–Called when a department opens or closes. Opening one closes the one that was open, which is reported first.
classNamestring–Class on the root element.

Keyboard interactions

KeysAction
TabMoves to the period switch, then into the department list, then out of the block.
Arrow left / Arrow rightOn the period switch, changes the reporting window.
Arrow up / Arrow downIn the department list, moves to the previous or next department.
Home / EndIn the department list, jumps to the first or last department.
Enter / SpaceOpens or closes the budget lines of the department in focus.

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