All Taste components
Settings
Plan & usage
The current plan and price, how much of each limit is used, and the card on file.
plan header · 4 usage meters · near-limit warning · payment method
Growth plan
Active₹2,499/ month
Renews on 1 Nov 2026 · billed monthly
Bookings this month1,840 / 2,500
Team seats5 / 5
All seats in use. Add seats to invite more people.
Storage18.4 GB / 50 GB
SMS credits920 / 1,000
Running low. Top up to keep reminders going.
Card ending 4821
Expires 08/28
import { CreditCard } from "lucide-react";
import { cn } from "@/lib/utils";
export interface Meter { label: string; used: number; limit: number; format?: (n: number) => string; warning?: string }
const n = (v: number) => v.toLocaleString("en-IN");
const sample: Meter[] = [
{ label: "Bookings this month", used: 1840, limit: 2500 },
{ label: "Team seats", used: 5, limit: 5, warning: "All seats in use. Add seats to invite more people." },
{ label: "Storage", used: 18.4, limit: 50, format: (v) => v + " GB" },
{ label: "SMS credits", used: 920, limit: 1000, warning: "Running low. Top up to keep reminders going." },
];
export function PlanUsageCard({
plan = "Growth plan", price = "₹2,499", cadence = "month", renews = "1 Nov 2026",
meters = sample, card = { last4: "4821", expires: "08/28" }, onUpgrade, onManage,
}: {
plan?: string; price?: string; cadence?: string; renews?: string; meters?: Meter[];
card?: { last4: string; expires: string }; onUpgrade?: () => void; onManage?: () => void;
}) {
return (
<section className="w-full max-w-[460px] rounded-lg border border-border bg-bg p-4">
<div className="flex flex-wrap items-start justify-between gap-3">
<div>
<div className="flex items-center gap-2">
<h3 className="text-sm font-medium">{plan}</h3>
<span className="rounded-full bg-success-soft px-2 py-0.5 text-xs font-medium text-success-fg">Active</span>
</div>
<p className="mt-1 flex items-baseline gap-1">
<span className="text-[22px] font-medium tracking-tight tabular-nums">{price}</span>
<span className="text-[13px] text-fg-subtle">/ {cadence}</span>
</p>
<p className="mt-0.5 text-[12.5px] text-fg-subtle">Renews on {renews} · billed monthly</p>
</div>
<button onClick={onUpgrade} className="h-[30px] rounded bg-primary px-2.5 text-[13px] font-medium text-primary-fg hover:bg-primary-hover">Upgrade</button>
</div>
<div className="mt-4 grid gap-3.5 border-t border-border pt-4">
{meters.map((m) => {
const pct = Math.min(100, Math.round((m.used / m.limit) * 100));
const warn = pct >= 90;
const f = m.format ?? n;
return (
<div key={m.label} className="grid gap-1.5 text-[13px]">
<div className="flex justify-between gap-2">
<span>{m.label}</span>
<span className="tabular-nums text-fg-muted"><b className="font-medium text-fg">{f(m.used)}</b> / {f(m.limit)}</span>
</div>
<div className="h-1.5 overflow-hidden rounded-full bg-surface-2" role="progressbar" aria-label={m.label}
aria-valuenow={pct} aria-valuemin={0} aria-valuemax={100}>
<div className={cn("h-full rounded-full", warn ? "bg-warning" : "bg-primary")} style={{ width: pct + "%" }} />
</div>
{warn && m.warning && <p className="text-xs text-warning-fg">{m.warning}</p>}
</div>
);
})}
</div>
<div className="mt-4 flex items-center gap-3 rounded border border-border p-3 text-[13px]">
<span className="grid h-7 w-9 place-items-center rounded bg-surface-2 text-fg-muted"><CreditCard className="size-4" aria-hidden /></span>
<div className="min-w-0 flex-1">
<p className="font-medium tabular-nums">Card ending {card.last4}</p>
<p className="text-[12.5px] text-fg-subtle">Expires {card.expires}</p>
</div>
<button onClick={onManage} className="h-[30px] rounded border border-border-strong px-2.5 text-[13px] font-medium hover:bg-surface">Manage billing</button>
</div>
</section>
);
}
The code uses the Taste Tailwind preset. Make yours on the Taste page with Export my system.