Mohamed Uvaish

Data Table

Component 32

About

Invoice table on TanStack Table: sortable columns with aria-sort, search, row selection with a bulk bar, a column menu, pagination and an empty state that offers to clear the search. Light and dark. Part of the Layro System: layro.vercel.app

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds Data Table to your project and fits it to your theme.

Code

How Data Table is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

import * as React from "react";
import { Button, DataTable, type ColumnDef } from "@/components/ui/data-table-bulk-actions";
import { Download, Plus } from "lucide-react";

/* Northwind Studio's invoices: 23 rows across seven customers. Sort a
   column, search "vela", select rows for the bulk bar, hide a column, or
   search for something that is not there to see the empty state. */

type Invoice = { number: string; customer: string; date: string; amount: number; status: "paid" | "open" | "failed" };
const CUSTOMERS = ["Northwind Studio", "Vela Labs", "Tallyworks", "Harbor & Co", "Juniper Health", "Ostrom Legal", "Kite Robotics"];
const STATUS: Invoice["status"][] = ["paid", "paid", "open", "paid", "failed", "paid", "open"];
const INVOICES: Invoice[] = Array.from({ length: 23 }, (_, i) => ({
  number: `INV-2026-${String(914 - i).padStart(4, "0")}`,
  customer: CUSTOMERS[i % CUSTOMERS.length],
  date: `${String(28 - (i % 27)).padStart(2, "0")} Sep 2026`,
  amount: [8900, 24900, 2900, 10100, 8900, 49900, 17800][i % 7],
  status: STATUS[i % STATUS.length],
}));
const money = (c: number) => `$${(c / 100).toLocaleString("en-US", { minimumFractionDigits: 2 })}`;
const TONE = {
  paid: "bg-emerald-500/12 text-emerald-700 dark:text-emerald-400",
  open: "bg-amber-500/15 text-amber-800 dark:text-amber-300",
  failed: "bg-red-500/10 text-red-700 dark:text-red-400",
};

const COLUMNS: ColumnDef<Invoice, any>[] = [
  { accessorKey: "number", header: "Invoice", cell: ({ getValue }) => <span className="font-medium tabular-nums">{getValue<string>()}</span> },
  { accessorKey: "customer", header: "Customer" },
  { accessorKey: "date", header: "Date", meta: { label: "Date" } },
  { accessorKey: "amount", header: "Amount", meta: { align: "right" }, cell: ({ getValue }) => <span className="tabular-nums">{money(getValue<number>())}</span> },
  {
    accessorKey: "status",
    header: "Status",
    cell: ({ getValue }) => {
      const s = getValue<Invoice["status"]>();
      return (
        <span className={`inline-flex h-[22px] items-center gap-1.5 rounded-full px-2 text-[11.5px] font-medium ${TONE[s]}`}>
          <span aria-hidden className="size-1.5 rounded-full bg-current" />
          {s[0].toUpperCase() + s.slice(1)}
        </span>
      );
    },
  },
];

export default function DataTableDemo() {
  return (
    <div className="flex min-h-screen w-full items-center justify-center bg-background p-6">
      <div className="w-full max-w-[860px] min-w-0 rounded-[18px] [corner-shape:squircle] bg-card p-5 ring-1 ring-border sm:p-6">
        <div className="mb-4 flex flex-wrap items-end justify-between gap-3">
          <div>
            <h2 className="text-[18px] font-semibold tracking-[-0.01em]">Invoices</h2>
            <p className="mt-1 text-[13px] text-muted-foreground">September 2026 · 23 invoices from 7 customers</p>
          </div>
          <Button><Plus /> New invoice</Button>
        </div>
        <DataTable
          label="Invoices"
          data={INVOICES}
          columns={COLUMNS}
          searchPlaceholder="Search invoices"
          selectable
          columnToggle
          pageSize={7}
          getRowId={(r) => r.number}
          bulkActions={(rows) => (
            <Button variant="outline"><Download /> Export {rows.length}</Button>
          )}
        />
      </div>
    </div>
  );
}

Dependencies

More by Mohamed Uvaish

View all
  • Signature Pad

    Signature Pad

    420
  • Folder Card

    Folder Card

    336
  • Share Dialog

    Share Dialog

    308
  • Kanban Board

    Kanban Board

    249
  • Notification Panel

    Notification Panel

    102
  • Charts & KPI Cards

    Charts & KPI Cards

    86
  • Rich Text Editor

    Rich Text Editor

    44
  • Command Menu

    Command Menu

    34

Explore more

Part of Layro System — browse the full library on 21st.dev.