Staaarter

Billing Departmental Billing Split

A departmental billing split block for dividing the cost of a shared resource, like a cluster or a premium support contract, across internal cost centers. Each department gets an editable percentage input and a computed dollar amount, a stacked bar visualizes the split, and the save button stays disabled until the percentages add up to exactly 100%. Built with shadcn/ui Input and Button components, Lucide icons, and Tailwind CSS.

By Staaarter Team
Billing
Updated June 8, 2026
Docs
Live preview

Docs

Installation

A real shadcn registry command, not a copy-paste stand-in: it fetches this block plus its input, label, button dependencies and any missing npm packages, and installs them straight into your project.

npx shadcn add https://staaarter.com/r/billing-departmental-billing-split.json

Prefer not to use the CLI? Copy the source from the Code toggle above into src/components/blocks/billing/billing46.tsx instead.

Usage

The file also exports billing46Demo, the exact props behind the preview above. Spread it to get a working section in one line, then replace it with your own data.

import { Billing46, billing46Demo } from "@/components/blocks/billing/billing46";

export default function Page() {
  return <Billing46 {...billing46Demo} />;
}

Props

PropTypeDefaultDescription
headingstring"Departmental billing split"Block heading.
descriptionstring"Distribute this invoice's cost across departments by percentage."Supporting text under the heading.
totalAmountnumbernoneThe full invoice total being split, in dollars.
currencySymbolstring"$"Symbol used when formatting totalAmount and each department's share.
departmentsDepartmentSplit[]noneDepartments and their starting percentages, copied into local state so edits don't mutate the prop.
saveLabelstring"Save split"Label on the save button, disabled while the split doesn't total 100%.
classNamestringnoneExtra classes for the outer container.

Types

interface DepartmentSplit {
  id: string;
  name: string;
  percent: number;
}

Behavior notes

  • departments only seeds initial state, edits to any percentage input update local state, they don't write back to the prop.
  • Each percentage input is clamped between 0 and 100 on change, and any non-numeric entry falls back to 0 rather than leaving the field in an invalid state.
  • The total row sums every department's current percentage on every render and compares it to 100 with a rounding tolerance, so 33.33 times three still reads as balanced.
  • The stacked bar and the colored square next to each row share the same shade lookup, cycling through a fixed array of primary-color opacity steps by index rather than assigning arbitrary colors.
  • The save button is disabled whenever the split doesn't total exactly 100%, there's no partial-save or auto-normalize option built in.

Frequently asked questions