| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| Total | $750.00 | ||
<TableRoot>
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead>Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.invoice}>
<TableCell>{invoice.invoice}</TableCell>
<TableCell>{invoice.status}</TableCell>
<TableCell>{invoice.method}</TableCell>
<TableCell className="text-right">{invoice.amount}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>Total</TableCell>
<TableCell className="text-right">$750.00</TableCell>
</TableRow>
</TableFooter>
</TableRoot>
npx @left4code/cosmic-ui-cli@latest add table
This writes the component and everything it imports, then installs the packages it needs. Run npx @left4code/cosmic-ui-cli@latest initfirst if you haven't already.
No state machine here - a table doesn't need one, it's semantic HTML (table > thead/tbody/tfoot) wrapped in a horizontally scrolling container so wide tables don't blow out the layout on small screens. Or copy and paste the code below by hand.
import { twMerge } from "tailwind-merge";
function TableRoot({
children,
className,
}: React.PropsWithChildren<{ className?: string }>) {
return (
<div className="relative w-full overflow-x-auto">
<table className={twMerge(["w-full border-collapse", className])}>
{children}
</table>
</div>
);
}
function TableHeader({
children,
className,
}: React.PropsWithChildren<{ className?: string }>) {
return <thead className={twMerge(["border-b border-primary/30", className])}>{children}</thead>;
}
function TableBody({
children,
className,
}: React.PropsWithChildren<{ className?: string }>) {
return (
<tbody className={twMerge(["[&_tr:last-child]:border-0", className])}>{children}</tbody>
);
}
function TableFooter({
children,
className,
}: React.PropsWithChildren<{ className?: string }>) {
return (
<tfoot className={twMerge(["border-t border-primary/30 font-medium", className])}>
{children}
</tfoot>
);
}
function TableRow({
children,
className,
}: React.PropsWithChildren<{ className?: string }>) {
return (
<tr className={twMerge(["border-b border-primary/10 hover:bg-primary/5", className])}>
{children}
</tr>
);
}
function TableHead({
children,
className,
}: React.PropsWithChildren<{ className?: string }>) {
return (
<th
className={twMerge([
"h-10 px-4 text-left align-middle font-medium text-foreground/70",
className,
])}
>
{children}
</th>
);
}
function TableCell({
children,
className,
colSpan,
}: React.PropsWithChildren<{ className?: string; colSpan?: number }>) {
return (
<td colSpan={colSpan} className={twMerge(["p-4 align-middle", className])}>
{children}
</td>
);
}
function TableCaption({
children,
className,
}: React.PropsWithChildren<{ className?: string }>) {
return <caption className={twMerge(["mt-4 opacity-70", className])}>{children}</caption>;
}
export {
TableRoot,
TableHeader,
TableBody,
TableFooter,
TableRow,
TableHead,
TableCell,
TableCaption,
};
Update the import paths to match your project setup.
import {
TableRoot,
TableHeader,
TableBody,
TableFooter,
TableRow,
TableHead,
TableCell,
TableCaption,
} from "@/components/ui/table";
<TableRoot>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Role</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>Ada</TableCell>
<TableCell>Engineer</TableCell>
</TableRow>
</TableBody>
</TableRoot>