Billingsdk
blockdetailed-usage-tablesource: ok · hit
Detailed Usage Table
A detailed usage table component with resource consumption breakdown
npx shadcn add "https://billingsdk.com/r/detailed-usage-table.json"free
Where it goes
data-table
Use cases
dashboard
Tags auto-generated by rules on 9/24/2026 — empty means no evidence, not lack of support.
Dependencies
Bundle weight · lightRegistry dependencies
tablecardbadgeutils
Files2 · source cached 10/9/2026, 5:37:50 AM
src/registry/billingsdk/detailed-usage-table.tsx
"use client";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { cn } from "@/lib/utils";
export interface UsageResource {
name: string;
used: number;
limit: number;
percentage?: number;
unit?: string;
}
export interface DetailedUsageTableProps {
className?: string;
title?: string;
description?: string;
resources: UsageResource[];
}
export function DetailedUsageTable({
className,
title = "Detailed Usage",
description,
resources,
}: DetailedUsageTableProps) {
const formatNumber = (num: number) => {
return new Intl.NumberFormat().format(num);
};
const getPercentageBar = (percentage: number) => {
let bgColor = "bg-emerald-500";
if (percentage >= 90) bgColor = "bg-destructive";
else if (percentage >= 75) bgColor = "bg-orange-500";
return (
<div className="flex min-w-[120px] items-center gap-2">
<div className="bg-secondary h-2 flex-1 rounded-full">
<div
className={cn("h-2 rounded-full transition-all", bgColor)}
style={{ width: `${Math.max(0, Math.min(percentage, 100))}%` }}
/>
</div>
<span className="w-10 text-right text-xs font-medium tabular-nums">
{Math.round(percentage)}%
</span>
</div>
);
};
return (
<Card className={cn("w-full", className)}>
<CardHeader>
<CardTitle>{title}</CardTitle>
{description && <CardDescription>{description}</CardDescription>}
</CardHeader>
<CardContent>
<div className="overflow-x-auto rounded-md border">
<Table>
<TableCaption className="sr-only">
Detailed usage of resources
</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-[180px]">Resource</TableHead>
<TableHead className="text-right">Used</TableHead>
<TableHead className="text-right">Limit</TableHead>
<TableHead className="min-w-[160px] text-right">
Usage
</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{resources.length === 0 ? (
<TableRow>
<TableCell
colSpan={4}
className="text-muted-foreground h-24 text-center"
>
No resources found
</TableCell>
</TableRow>
) : (
resources.map((resource, index) => {
const percentage =
resource.percentage ??
(resource.limit > 0
? (resource.used / resource.limit) * 100
: 0);
const unit = resource.unit ? ` ${resource.unit}` : "";
return (
<TableRow key={resource.name || index}>
<TableCell className="font-medium">
{resource.name}
</TableCell>
<TableCell className="text-right tabular-nums">
{formatNumber(resource.used)}
{unit}
</TableCell>
<TableCell className="text-muted-foreground text-right tabular-nums">
{formatNumber(resource.limit)}
{unit}
</TableCell>
<TableCell className="text-right">
{getPercentageBar(percentage)}
</TableCell>
</TableRow>
);
})
)}
</TableBody>
</Table>
</div>
</CardContent>
</Card>
);
}
src/registry/billingsdk/demo/detailed-usage-table-demo.tsx
"use client";
import { DetailedUsageTable } from "@/registry/billingsdk/detailed-usage-table";
export function DetailedUsageTableDemo() {
return (
<DetailedUsageTable
title="Resource Usage"
description="Detailed breakdown of your resource consumption"
resources={[
{
name: "API Calls",
used: 12300,
limit: 20000,
// percentage will be automatically calculated as 61.5%
unit: "calls",
},
{ name: "Storage", used: 850, limit: 1000, percentage: 85, unit: "GB" },
{
name: "Team Members",
used: 4,
limit: 5,
// percentage will be automatically calculated as 80%
unit: "users",
},
{
name: "Bandwidth",
used: 1500,
limit: 2000,
percentage: 75,
unit: "GB",
},
{
name: "Emails",
used: 8500,
limit: 10000,
// percentage will be automatically calculated as 85%
unit: "emails",
},
]}
/>
);
}