# Billing Overview

> An animated billing overview for React and shadcn, with usage meters that warn at 80% and a cancel flow.

A workspace's billing at a glance: the next invoice rolls, usage meters turn warning at 80%, and cancelling is a Dialog with a reason step, then a confirm step whose primary label morphs.

- Tier: Eased Pro
- Interaction: Press
- Page: https://eased.dev/components/billing-overview
- Installs: motion

## Install

Billing Overview ships with Eased Pro (https://eased.dev/#pricing). Members add the `@eased-pro` registry with their token (https://eased.dev/account), then run:

```bash
npx shadcn add @eased-pro/billing-overview
```

A workspace's billing at a glance: the next invoice, usage meters that turn warning at 80%, and a cancel flow with a reason step. Built on Dialog, Radio Group, Auto Height and Number Roll.

## When to use

- The Billing tab of a SaaS settings page.
- When usage limits matter: events, seats, storage.
- When cancelling should ask why, then confirm, without leaving the page.

## When not to use

- Comparing plans to buy: use a pricing table or [Usage-based Pricing Calculator](/components/usage-pricing-calculator).
- A list of past invoices: use a Table.

## Usage

```tsx example.tsx
import { BillingOverview } from "@/components/eased/billing-overview/billing-overview";

<BillingOverview
  plan={{ name: "Growth", interval: "month", renewsAt: Date.UTC(2026, 9, 31) }}
  lines={[{ id: "plan", label: "Growth plan", amount: 99 }, { id: "sync", label: "Warehouse sync", amount: 30 }]}
  usage={[
    { id: "events", label: "Events", used: 1_642_000, limit: 2_000_000, overage: "Past 2M, events cost $0.09 per 1K." },
    { id: "seats", label: "Seats", used: 7, limit: 10 },
  ]}
  card={{ brand: "Visa", last4: "4417" }}
  cancelReasons={[{ id: "price", label: "It costs too much" }, { id: "other", label: "Something else" }]}
  onCancel={(reason) => api.cancel(reason)}
  actions={<Button size="sm">Change plan</Button>}
/>
```

## API reference

### BillingOverview

| Prop | Type | Default | Description |
|---|---|---|---|
| `plan` | `{ name, interval, renewsAt }` | | |
| `lines` | `{ id, label, amount }[]` | | The upcoming invoice; its total is the focal number and the lines are listed under it. |
| `maxLines` | `number` | `3` | Past this, the first `maxLines - 1` lines show and the rest fold behind an "N more" disclosure. |
| `usage` | `BillingUsage[]` | `[]` | `{ id, label, used, limit, format?, overage? }`. A meter turns warning at 80%; `overage` explains the cost. |
| `card` | `{ brand, last4, expires? }` | | Card on file. |
| `cancelReasons` | `{ id, label }[]` | `[]` | The cancel flow's first step. No reasons, no Cancel button. |
| `canceled` / `defaultCanceled` | `boolean` | `false` | The plan ends at `renewsAt`. |
| `onCancel` / `onResume` | `(reason) => void` / `() => void` | | |
| `actions` | `ReactNode` | | Leading footer slot. |
| `currency` / `locale` | `string` | `"USD"` / `"en-US"` | |

`UsageMeter` (from `_primitives/saas-core`) is the meter on its own.

## Keyboard

| Key | Action |
|---|---|
| `Enter` on Cancel plan | Opens the dialog; focus moves to the first reason. |
| `↑` / `↓` | Choose a reason. |
| `Escape` | Closes the dialog and returns focus to Cancel plan. |
| `Enter` / `Space` on N more | Shows or hides the folded invoice lines. |

## Accessibility

- Meters use `role="meter"` with a spoken value ("1.64M of 2M, 82%").
- The dialog is Base UI's: focus is trapped, labelled by its title and described by its description.
- Continue stays disabled until a reason is chosen; the final step names the consequence before the destructive button.

## Motion

The invoice rolls on the snappy spring; meter fills slide in on `smooth` and recolour at 80%. In the dialog the body cross-fades between steps with a blur while its height springs (Auto Height), and the primary button morphs from "Continue" to "Cancel plan" rather than swapping. The "N more" lines unfold on Auto Height. Cancelling rolls the invoice and its lines to zero, folds the lines away and unfolds a Resume banner in their place. Reduced motion: values change at once and steps fade.

## Notes for AI

Use it on a billing settings page. Pass the upcoming invoice as `lines` so the total is derived, and give every usage meter that can cost money an `overage` sentence.

Don't build a separate confirm dialog: the two-step flow is inside. Don't colour meters red at their limit; a limit is information (warning), not an error.

## Related

- [Usage-based Pricing Calculator](/components/usage-pricing-calculator): estimating before buying.
- [Dialog](/components/dialog): the cancel flow's surface.
