# Invoice History Table

> Billing history table displaying invoices with date, description, amount, payment status badges, and download buttons. Perfect for account billing pages and payment management dashboards.

A shadcn/ui block from the [@beste-ui](https://ui.beste.co) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/beste-ui/settings64).

- Page, with a live preview: https://shadcn.exchange/r/beste-ui/settings64
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/beste-ui/settings64-light-40789c6989a542e8.png
- Registry item: https://ui.beste.co/r/settings64.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://ui.beste.co/r/settings64.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- npm packages: `clsx`, `lucide-react`, `tailwind-merge`
- Registry items: `badge`, `button`, `table`

## Files

### `registry/settings64/settings64.tsx`

```tsx
"use client";

import {
  CheckCircle,
  Clock,
  CreditCard,
  Download,
  FileText,
  XCircle,
} from "lucide-react";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";

import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import Link from "next/link";
import { cn } from "@/lib/utils";

interface Invoice {
  date: string;
  amount: string;
  status: "paid" | "pending" | "failed";
  description: string;
  invoiceNumber: string;
  downloadUrl?: string;
}

interface Settings64Props {
  badge?: {
    label: string;
    variant?: "default" | "secondary" | "outline";
  };
  heading?: string;
  description?: string;
  invoices?: Invoice[];
  labels?: {
    date?: string;
    description?: string;
    amount?: string;
    status?: string;
    paid?: string;
    pending?: string;
    failed?: string;
    download?: string;
    noInvoices?: string;
    viewAll?: string;
  };
  viewAllUrl?: string;
  className?: string;
}

export const settings64Demo: Settings64Props = {
  badge: { label: "Billing", variant: "secondary" },
  heading: "Billing History",
  description: "View and download your past invoices and payment history.",
  invoices: [
    {
      date: "Jan 1, 2024",
      amount: "$29.00",
      status: "paid",
      description: "Pro Plan - Monthly",
      invoiceNumber: "INV-2024-001",
      downloadUrl: "https://beste.co",
    },
    {
      date: "Dec 1, 2023",
      amount: "$29.00",
      status: "paid",
      description: "Pro Plan - Monthly",
      invoiceNumber: "INV-2023-012",
      downloadUrl: "https://beste.co",
    },
    {
      date: "Nov 1, 2023",
      amount: "$29.00",
      status: "paid",
      description: "Pro Plan - Monthly",
      invoiceNumber: "INV-2023-011",
      downloadUrl: "https://beste.co",
    },
    {
      date: "Oct 1, 2023",
      amount: "$29.00",
      status: "failed",
      description: "Pro Plan - Monthly",
      invoiceNumber: "INV-2023-010",
      downloadUrl: "https://beste.co",
    },
    {
      date: "Sep 1, 2023",
      amount: "$29.00",
      status: "paid",
      description: "Pro Plan - Monthly",
      invoiceNumber: "INV-2023-009",
      downloadUrl: "https://beste.co",
    },
  ],
  labels: {
    date: "Date",
    description: "Description",
    amount: "Amount",
    status: "Status",
    paid: "Paid",
    pending: "Pending",
    failed: "Failed",
    download: "Download",
    noInvoices: "No invoices yet",
    viewAll: "View All Invoices",
  },
  viewAllUrl: "https://beste.co",
};

export function Settings64({
  badge,
  heading,
  description,
  invoices = [],
  labels = {},
  viewAllUrl,
  className,
}: Settings64Props) {
  const {
    date: dateLabel,
    description: descLabel,
    amount: amountLabel,
    status: statusLabel,
    paid: paidLabel,
    pending: pendingLabel,
    failed: failedLabel,
    download: downloadLabel,
    noInvoices: noInvoicesLabel,
    viewAll: viewAllLabel,
  } = labels;

  const getStatusBadge = (invoiceStatus: Invoice["status"]) => {
    switch (invoiceStatus) {
      case "paid":
        return (
          <Badge
            variant="outline"
            className="border-emerald-500/20 bg-emerald-500/10 text-emerald-600 font-normal"
          >
            <CheckCircle className="size-3" />
            {paidLabel}
          </Badge>
        );
      case "pending":
        return (
          <Badge
            variant="outline"
            className="border-amber-500/20 bg-amber-500/10 text-amber-600 font-normal"
          >
            <Clock className="size-3" />
            {pendingLabel}
          </Badge>
        );
      case "failed":
        return (
          <Badge
            variant="outline"
            className="border-rose-500/20 bg-rose-500/10 text-rose-600 font-normal"
          >
            <XCircle className="size-3" />
            {failedLabel}
          </Badge>
        );
    }
  };

  return (
    <section className={cn("py-16 md:py-24 w-full", className)}>
      <div className="mx-auto max-w-4xl px-4 md:px-6">
        <div className="flex flex-col gap-6">
          <div className="flex flex-col gap-3">
            {badge?.label && (
              <Badge variant={badge.variant} className="w-fit">
                <CreditCard className="mr-1 size-3" />
                {badge.label}
              </Badge>
            )}
            {heading && (
              <h2 className="text-2xl font-bold tracking-tight md:text-3xl">
                {heading}
              </h2>
            )}
            {description && (
              <p className="text-muted-foreground">{description}</p>
            )}
          </div>

          {invoices.length === 0 ? (
            <div className="flex flex-col items-center gap-3 rounded-lg border bg-card p-8 text-center">
              <FileText className="size-12 text-muted-foreground" />
              <p className="text-muted-foreground">{noInvoicesLabel}</p>
            </div>
          ) : (
            <div className="rounded-lg border bg-card">
              <Table>
                <TableHeader>
                  <TableRow className="bg-muted/50">
                    <TableHead className="px-4">{dateLabel}</TableHead>
                    <TableHead className="px-4">{descLabel}</TableHead>
                    <TableHead className="px-4">{amountLabel}</TableHead>
                    <TableHead className="px-4 text-center">
                      {statusLabel}
                    </TableHead>
                    <TableHead className="px-4 w-12 text-right">
                      {downloadLabel}
                    </TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {invoices.map((invoice, index) => (
                    <TableRow key={index}>
                      <TableCell className="px-4">
                        <div className="font-medium">{invoice.date}</div>
                        <div className="text-xs text-muted-foreground">
                          {invoice.invoiceNumber}
                        </div>
                      </TableCell>
                      <TableCell className="px-4">
                        {invoice.description}
                      </TableCell>
                      <TableCell className="px-4 font-medium">
                        {invoice.amount}
                      </TableCell>
                      <TableCell className="px-4 text-center">
                        {getStatusBadge(invoice.status)}
                      </TableCell>
                      <TableCell className="px-4 text-right">
                        {invoice.downloadUrl ? (
                          <Button variant="ghost" size="icon" asChild>
                            <Link href={invoice.downloadUrl}>
                              <Download className="size-4" />
                            </Link>
                          </Button>
                        ) : (
                          <Button variant="ghost" size="icon" disabled>
                            <Download className="size-4" />
                          </Button>
                        )}
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </div>
          )}

          {invoices.length > 0 && viewAllUrl && (
            <div className="flex justify-center">
              <Button variant="outline" asChild>
                <Link href={viewAllUrl}>{viewAllLabel}</Link>
              </Button>
            </div>
          )}
        </div>
      </div>
    </section>
  );
}
```
