Billing Account
blockfinanceStripe-style account billing page: current-plan card with Pro badge, price and renewal date plus Upgrade / Cancel actions, usage meters for seats and projects, a payment-method row with update and delete actions, and a compact billing-history list with paid badges and per-invoice downloads.
Installation
$pnpm dlx uipkge-ng@latest add billing-account$npx uipkge-ng@latest add billing-account$yarn dlx uipkge-ng@latest add billing-account$bunx uipkge-ng@latest add billing-accountManifest:
https://uipkge.dev/r/angular/billing-account.jsonInstalls to:src/app/components/blocks/billing-account/Variants
Loading interactive previews…
Loading interactive previews…
Schema
Type aliases exported from this item's source. Use these to shape the data you pass in.
UsageMetricinterface UsageMetric {
label: string
used: number
total: number
}Invoiceinterface Invoice {
id: string
date: string
amount: string
status: 'Paid' | 'Open' | 'Past due'
}Files installed (2)
src/app/components/blocks/billing-account/billing-account.component.ts7.2 kB
// Stripe-style account billing page: current-plan card with Pro badge, price and renewal // date plus Upgrade / Cancel actions, usage meters for seats and projects, a payment-method // row with update and delete actions, and a compact billing-history list with paid badges // and per-invoice downloads. Port of the React block 1:1. import { ChangeDetectionStrategy, Component, Input } from '@angular/core' import { CreditCard, Download, LucideAngularModule, Trash2 } from 'lucide-angular' import { cn } from '@/lib/utils' import { UiBadgeComponent } from '@/ui/badge/badge.component' import { UiButtonComponent } from '@/ui/button/button.component' import { UiCardComponent, UiCardContentComponent, UiCardDescriptionComponent, UiCardHeaderComponent, UiCardTitleComponent, } from '@/ui/card/card.component' import { UiProgressComponent } from '@/ui/progress/progress.component' import { UiSeparatorComponent } from '@/ui/separator/separator.component' interface UsageMetric { label: string used: number total: number } interface Invoice { id: string date: string amount: string status: 'Paid' | 'Open' | 'Past due' } const plan = { name: 'Pro', price: '$49', cadence: 'month', renewalDate: 'September 12, 2026', } const usage: UsageMetric[] = [ { label: 'Seats', used: 18, total: 20 }, { label: 'Projects', used: 7, total: 10 }, ] const paymentMethod = { brand: 'Visa', last4: '4242', expiry: '04/28', } const invoices: Invoice[] = [ { id: 'inv-2026-08', date: 'Aug 12, 2026', amount: '$49.00', status: 'Paid' }, { id: 'inv-2026-07', date: 'Jul 12, 2026', amount: '$49.00', status: 'Paid' }, { id: 'inv-2026-06', date: 'Jun 12, 2026', amount: '$49.00', status: 'Paid' }, { id: 'inv-2026-05', date: 'May 12, 2026', amount: '$49.00', status: 'Paid' }, ] @Component({ changeDetection: ChangeDetectionStrategy.Eager, selector: 'ui-billing-account, [ui-billing-account]', standalone: true, // React renders the root <div> itself: the host stays out of layout and `class` goes to the root. host: { '[attr.class]': '"contents"' }, imports: [ LucideAngularModule, UiBadgeComponent, UiButtonComponent, UiCardComponent, UiCardContentComponent, UiCardDescriptionComponent, UiCardHeaderComponent, UiCardTitleComponent, UiProgressComponent, UiSeparatorComponent, ], template: ` <div data-slot="billing-account" [class]="rootClass"> <div ui-card> <div ui-card-header> <div class="flex items-center gap-2"> <h3 ui-card-title>Current plan</h3> <span ui-badge>{{ plan.name }}</span> </div> <p ui-card-description>Your subscription renews automatically each month.</p> </div> <div ui-card-content class="space-y-4"> <div class="flex flex-wrap items-end justify-between gap-4"> <div> <p class="text-2xl font-bold tracking-tight"> {{ plan.price }} <span class="text-muted-foreground text-sm font-normal">/ {{ plan.cadence }}</span> </p> <p class="text-muted-foreground mt-1 text-xs">Renews on {{ plan.renewalDate }}</p> </div> <div class="flex items-center gap-2"> <button ui-button size="sm">Upgrade</button> <button ui-button variant="ghost" size="sm" class="text-destructive hover:text-destructive"> Cancel subscription </button> </div> </div> </div> </div> <div ui-card> <div ui-card-header> <h3 ui-card-title>Usage</h3> <p ui-card-description>Consumption against your plan limits this cycle.</p> </div> <div ui-card-content class="space-y-5"> @for (metric of usageMetrics; track metric.label) { <div class="space-y-2"> <div class="flex items-center justify-between text-sm"> <span class="font-medium">{{ metric.label }}</span> <span class="text-muted-foreground text-xs tabular-nums"> {{ metric.used }} of {{ metric.total }} used </span> </div> <ui-progress [value]="(metric.used / metric.total) * 100" /> </div> } </div> </div> <div ui-card> <div ui-card-header> <h3 ui-card-title>Payment method</h3> <p ui-card-description>Charged when your subscription renews.</p> </div> <div ui-card-content> <div class="flex items-center justify-between gap-4"> <div class="flex items-center gap-3"> <div class="bg-muted text-muted-foreground border-border flex size-9 shrink-0 items-center justify-center rounded-md border shadow-xs" aria-hidden="true" > <lucide-icon [img]="CreditCard" class="size-4" /> </div> <div> <p class="text-sm font-medium tabular-nums">•••• •••• •••• {{ paymentMethod.last4 }}</p> <p class="text-muted-foreground text-xs"> {{ paymentMethod.brand }} · Expires {{ paymentMethod.expiry }} </p> </div> </div> <div class="flex items-center gap-1"> <button ui-button variant="ghost" size="sm">Update</button> <button ui-button variant="ghost" size="icon-sm" aria-label="Delete payment method"> <lucide-icon [img]="Trash2" class="text-muted-foreground size-4" /> </button> </div> </div> </div> </div> <div ui-card> <div ui-card-header> <h3 ui-card-title>Billing history</h3> <p ui-card-description>Invoices from the last 12 months.</p> </div> <div ui-card-content> <ul class="-my-2 divide-y"> @for (invoice of invoiceList; track invoice.id) { <li class="flex items-center justify-between gap-4 py-3"> <div class="min-w-0"> <p class="text-sm font-medium">{{ invoice.date }}</p> <p class="text-muted-foreground text-xs tabular-nums">{{ invoice.amount }}</p> </div> <div class="flex items-center gap-2"> <span ui-badge variant="success">{{ invoice.status }}</span> <ui-separator orientation="vertical" class="!h-4" /> <button ui-button variant="ghost" size="icon-sm" aria-label="Download invoice"> <lucide-icon [img]="Download" class="text-muted-foreground size-4" /> </button> </div> </li> } </ul> </div> </div> </div> `, }) export class UiBillingAccountComponent { protected readonly CreditCard = CreditCard protected readonly Download = Download protected readonly Trash2 = Trash2 protected readonly plan = plan protected readonly usageMetrics = usage protected readonly paymentMethod = paymentMethod protected readonly invoiceList = invoices @Input('class') className?: string get rootClass(): string { return cn('mx-auto w-full max-w-2xl space-y-6', this.className) } }src/app/components/blocks/billing-account/index.ts0.1 kB
export { UiBillingAccountComponent } from './billing-account.component'
Raw manifest:https://uipkge.dev/r/angular/billing-account.json