Table
Semantic HTML table with styled header, body, footer, and caption slots.
Examples
Actions
A table showing actions for each row using a <DropdownMenu /> component.
| Product | Price | Actions |
|---|---|---|
| Wireless Mouse | $29.99 | |
| Mechanical Keyboard | $129.99 | |
| USB-C Hub | $49.99 |
import { Button } from "@codefast/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@codefast/ui/dropdown-menu";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@codefast/ui/table";
import { MoreHorizontalIcon } from "lucide-react";
export function TableActions() {
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>Product</TableHead>
<TableHead>Price</TableHead>
<TableHead className="text-end">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell className="font-medium">Wireless Mouse</TableCell>
<TableCell>$29.99</TableCell>
<TableCell className="text-end">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="size-8">
<MoreHorizontalIcon />
<span className="sr-only">Open menu</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem>Duplicate</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem variant="destructive">Delete</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">Mechanical Keyboard</TableCell>
<TableCell>$129.99</TableCell>
<TableCell className="text-end">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="size-8">
<MoreHorizontalIcon />
<span className="sr-only">Open menu</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem>Duplicate</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem variant="destructive">Delete</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
<TableRow>
<TableCell className="font-medium">USB-C Hub</TableCell>
<TableCell>$49.99</TableCell>
<TableCell className="text-end">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="size-8">
<MoreHorizontalIcon />
<span className="sr-only">Open menu</span>
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuItem>Edit</DropdownMenuItem>
<DropdownMenuItem>Duplicate</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem variant="destructive">Delete</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</TableCell>
</TableRow>
</TableBody>
</Table>
);
}
RTL
Right-to-left layout support for languages such as Arabic and Hebrew.
Translations are AI-generated for demonstration and may be imperfect.
| الفاتورة | الحالة | الطريقة | المبلغ |
|---|---|---|---|
| INV001 | مدفوع | بطاقة ائتمانية | $250.00 |
| INV002 | قيد الانتظار | PayPal | $150.00 |
| INV003 | غير مدفوع | تحويل بنكي | $350.00 |
| INV004 | مدفوع | بطاقة ائتمانية | $450.00 |
| INV005 | مدفوع | PayPal | $550.00 |
| INV006 | قيد الانتظار | تحويل بنكي | $200.00 |
| INV007 | غير مدفوع | بطاقة ائتمانية | $300.00 |
| المجموع | $2,500.00 | ||
import {
Table,
TableBody,
TableCaption,
TableCell,
TableFooter,
TableHead,
TableHeader,
TableRow,
} from "@codefast/ui/table";
import type { Translations } from "#/features/components-catalog/components/detail/language";
import { useTranslation } from "#/features/components-catalog/components/detail/language-context";
const translations: Translations = {
en: {
dir: "ltr",
values: {
caption: "A list of your recent invoices.",
invoice: "Invoice",
status: "Status",
method: "Method",
amount: "Amount",
paid: "Paid",
pending: "Pending",
unpaid: "Unpaid",
creditCard: "Credit Card",
paypal: "PayPal",
bankTransfer: "Bank Transfer",
total: "Total",
},
},
ar: {
dir: "rtl",
values: {
caption: "قائمة بفواتيرك الأخيرة.",
invoice: "الفاتورة",
status: "الحالة",
method: "الطريقة",
amount: "المبلغ",
paid: "مدفوع",
pending: "قيد الانتظار",
unpaid: "غير مدفوع",
creditCard: "بطاقة ائتمانية",
paypal: "PayPal",
bankTransfer: "تحويل بنكي",
total: "المجموع",
},
},
he: {
dir: "rtl",
values: {
caption: "רשימת החשבוניות האחרונות שלך.",
invoice: "חשבונית",
status: "סטטוס",
method: "שיטה",
amount: "סכום",
paid: "שולם",
pending: "ממתין",
unpaid: "לא שולם",
creditCard: "כרטיס אשראי",
paypal: "PayPal",
bankTransfer: "העברה בנקאית",
total: 'סה"כ',
},
},
};
const invoices = [
{
invoice: "INV001",
paymentStatus: "paid" as const,
totalAmount: "$250.00",
paymentMethod: "creditCard" as const,
},
{
invoice: "INV002",
paymentStatus: "pending" as const,
totalAmount: "$150.00",
paymentMethod: "paypal" as const,
},
{
invoice: "INV003",
paymentStatus: "unpaid" as const,
totalAmount: "$350.00",
paymentMethod: "bankTransfer" as const,
},
{
invoice: "INV004",
paymentStatus: "paid" as const,
totalAmount: "$450.00",
paymentMethod: "creditCard" as const,
},
{
invoice: "INV005",
paymentStatus: "paid" as const,
totalAmount: "$550.00",
paymentMethod: "paypal" as const,
},
{
invoice: "INV006",
paymentStatus: "pending" as const,
totalAmount: "$200.00",
paymentMethod: "bankTransfer" as const,
},
{
invoice: "INV007",
paymentStatus: "unpaid" as const,
totalAmount: "$300.00",
paymentMethod: "creditCard" as const,
},
];
export function TableRtl() {
const { dir, t } = useTranslation(translations, "ar");
return (
<Table dir={dir}>
<TableCaption>{t.caption}</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-25">{t.invoice}</TableHead>
<TableHead>{t.status}</TableHead>
<TableHead>{t.method}</TableHead>
<TableHead className="text-end">{t.amount}</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.invoice}>
<TableCell className="font-medium">{invoice.invoice}</TableCell>
<TableCell>{t[invoice.paymentStatus]}</TableCell>
<TableCell>{t[invoice.paymentMethod]}</TableCell>
<TableCell className="text-end">{invoice.totalAmount}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>{t.total}</TableCell>
<TableCell className="text-end">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
);
}
Usage
The minimal import and composition — see Examples below for styled, real-world variants.
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@codefast/ui/table";
export function TableUsage() {
return (
<Table>
<TableHeader>
<TableRow>
<TableHead>Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>INV001</TableCell>
<TableCell>Paid</TableCell>
<TableCell>$250.00</TableCell>
</TableRow>
</TableBody>
</Table>
);
}
Anatomy
How the parts nest — every slot the component exposes, in composition order.
Features
- Wraps itself in a horizontally-scrollable container automatically — no separate overflow wrapper needed for wide tables.
- TableRow highlights itself on data-selected or aria-expanded with no extra classes required.
- Thin styled wrappers over real <table>/<thead>/<tbody>/<tfoot> elements — full native semantics and copy/paste behaviour.
API reference
Props for each part of the component. All native element props are also forwarded.
TableHeader
Maps to <thead>.
childrenReactNodeTableRow elements for the header.
TableBody
Maps to <tbody>.
childrenReactNodeTableRow elements for the body.
TableFooter
Maps to <tfoot>.
childrenReactNodeTableRow elements for the footer.
TableRow
Maps to <tr>. Highlights itself on data-selected or aria-expanded.
childrenReactNodeTableHead or TableCell elements.
TableHead
A header cell — maps to <th>.
childrenReactNodeThe column heading content.
TableCell
A body cell — maps to <td>.
childrenReactNodeThe cell content.
TableCaption
childrenReactNodeA caption describing the table for assistive tech.
Accessibility
Built to be keyboard-navigable and screen-reader friendly out of the box.
- Renders real <table> markup, so semantics and navigation come for free.
- Use TableCaption (or aria-label) to describe what the table contains.
- Keep header cells in <th> so columns are announced.
Guidelines
Conventions that keep usage consistent across an app.
Do
- Use for genuinely tabular data with shared columns.
- Right-align numeric columns and use tabular figures.
Don’t
- Don’t use a table purely for layout.
- Don’t drop the header row — it names the columns.
Explore further
Ready to integrate?
Follow the Getting Started guide to install @codefast/ui, or browse the full component gallery.