A flexible, accessible table component with support for multiple sizes, text alignment options, and interactive states. Includes sortable headers, hover effects, and row selection states for building data-rich interfaces.
| Name | Status | |
|---|---|---|
| Sarah Johnson | sarah@example.com | Active |
| Michael Chen | michael@example.com | Active |
| Emily Rodriguez | emily@example.com | Inactive |
1"use client";
2
3import {
4Table,
5TableBody,
6TableCell,
7TableHead,
8TableHeaderCell,
9TableRow,
10} from "@/components/component-x/table";
11
12export function TablePreview() {
13return (
14 <div className="w-full p-4">
15 <Table size="md">
16 <TableHead>
17 <TableRow>
18 <TableHeaderCell>Name</TableHeaderCell>
19 <TableHeaderCell>Email</TableHeaderCell>
20 <TableHeaderCell align="right">Status</TableHeaderCell>
21 </TableRow>
22 </TableHead>
23 <TableBody>
24 <TableRow>
25 <TableCell>Sarah Johnson</TableCell>
26 <TableCell>sarah@example.com</TableCell>
27 <TableCell align="right">Active</TableCell>
28 </TableRow>
29 <TableRow>
30 <TableCell>Michael Chen</TableCell>
31 <TableCell>michael@example.com</TableCell>
32 <TableCell align="right">Active</TableCell>
33 </TableRow>
34 <TableRow>
35 <TableCell>Emily Rodriguez</TableCell>
36 <TableCell>emily@example.com</TableCell>
37 <TableCell align="right">Inactive</TableCell>
38 </TableRow>
39 </TableBody>
40 </Table>
41 </div>
42);
43}
44
45
46Run the following command to add the component:
npx cx add table| Name | Status | |
|---|---|---|
| Sarah Johnson | sarah@example.com | Active |
| Michael Chen | michael@example.com | Active |
| Emily Rodriguez | emily@example.com | Inactive |
| Name | Status | |
|---|---|---|
| Sarah Johnson | sarah@example.com | Active |
| Michael Chen | michael@example.com | Active |
| Emily Rodriguez | emily@example.com | Inactive |
| Name | Status | |
|---|---|---|
| Sarah Johnson | sarah@example.com | Active |
| Michael Chen | michael@example.com | Active |
| Emily Rodriguez | emily@example.com | Inactive |
1"use client";
2
3import {
4Table,
5TableBody,
6TableCell,
7TableHead,
8TableHeaderCell,
9TableRow,
10} from "@/components/component-x/table";
11
12function capitalizeFirstLetter(str: string): string {
13if (!str) return str;
14return str.charAt(0).toUpperCase() + str.slice(1);
15}
16
17export function TableSizes() {
18const sizes = ["sm", "md", "lg"] as const;
19
20return (
21 <div className="w-full h-full overflow-y-auto flex flex-col gap-6 p-4">
22 {sizes.map((size) => (
23 <div key={size}>
24 <h3 className="text-sm font-semibold text-muted-foreground mb-3">
25 {capitalizeFirstLetter(size)} -{" "}
26 {size === "sm" ? "Compact" : size === "md" ? "Default" : "Spacious"}
27 </h3>
28 <Table size={size}>
29 <TableHead>
30 <TableRow>
31 <TableHeaderCell>Name</TableHeaderCell>
32 <TableHeaderCell>Email</TableHeaderCell>
33 <TableHeaderCell>Status</TableHeaderCell>
34 </TableRow>
35 </TableHead>
36 <TableBody>
37 <TableRow>
38 <TableCell>Sarah Johnson</TableCell>
39 <TableCell>sarah@example.com</TableCell>
40 <TableCell>Active</TableCell>
41 </TableRow>
42 <TableRow>
43 <TableCell>Michael Chen</TableCell>
44 <TableCell>michael@example.com</TableCell>
45 <TableCell>Active</TableCell>
46 </TableRow>
47 <TableRow>
48 <TableCell>Emily Rodriguez</TableCell>
49 <TableCell>emily@example.com</TableCell>
50 <TableCell>Inactive</TableCell>
51 </TableRow>
52 </TableBody>
53 </Table>
54 </div>
55 ))}
56 </div>
57);
58}
59
60| Name | Status | |
|---|---|---|
| Sarah Johnson | sarah@example.com | Active |
| Michael Chen | michael@example.com | Active |
| Emily Rodriguez | emily@example.com | Inactive |
| Name | Status | |
|---|---|---|
| Sarah Johnson | sarah@example.com | Active |
| Michael Chen | michael@example.com | Active |
| Emily Rodriguez | emily@example.com | Inactive |
| Name | Status | |
|---|---|---|
| Sarah Johnson | sarah@example.com | Active |
| Michael Chen | michael@example.com | Active |
| Emily Rodriguez | emily@example.com | Inactive |
1"use client";
2
3import {
4 Table,
5 TableBody,
6 TableCell,
7 TableHead,
8 TableHeaderCell,
9 TableRow,
10} from "@/components/component-x/table";
11
12function capitalizeFirstLetter(str: string): string {
13 if (!str) return str;
14 return str.charAt(0).toUpperCase() + str.slice(1);
15}
16
17export function TableAlignment() {
18 const alignments = ["left", "center", "right"] as const;
19
20 return (
21 <div className="w-full h-full overflow-y-auto flex flex-col gap-6">
22 {alignments.map((align) => (
23 <div key={align} className="flex-none w-full p-4">
24 <h3 className="text-sm font-semibold text-muted-foreground mb-3">
25 {capitalizeFirstLetter(align)} Alignment
26 </h3>
27 <Table>
28 <TableHead>
29 <TableRow>
30 <TableHeaderCell align={align}>Name</TableHeaderCell>
31 <TableHeaderCell align={align}>Email</TableHeaderCell>
32 <TableHeaderCell align={align}>Status</TableHeaderCell>
33 </TableRow>
34 </TableHead>
35 <TableBody>
36 <TableRow>
37 <TableCell align={align}>Sarah Johnson</TableCell>
38 <TableCell align={align}>sarah@example.com</TableCell>
39 <TableCell align={align}>Active</TableCell>
40 </TableRow>
41 <TableRow>
42 <TableCell align={align}>Michael Chen</TableCell>
43 <TableCell align={align}>michael@example.com</TableCell>
44 <TableCell align={align}>Active</TableCell>
45 </TableRow>
46 <TableRow>
47 <TableCell align={align}>Emily Rodriguez</TableCell>
48 <TableCell align={align}>emily@example.com</TableCell>
49 <TableCell align={align}>Inactive</TableCell>
50 </TableRow>
51 </TableBody>
52 </Table>
53 </div>
54 ))}
55 </div>
56 );
57}
58| Product | Status | Price |
|---|---|---|
| Laptop | In Stock | $999 |
| Mouse | In Stock | $29 |
| Keyboard | Low Stock | $79 |
| Monitor | Out of Stock | $349 |
Click rows to select them. 1 row(s) selected.
1"use client";
2
3import {
4 Table,
5 TableBody,
6 TableCell,
7 TableHead,
8 TableHeaderCell,
9 TableRow,
10} from "@/components/component-x/table";
11import { useState } from "react";
12
13export function TableInteractive() {
14 const [selectedRows, setSelectedRows] = useState<number[]>([1]);
15
16 const toggleRow = (index: number) => {
17 setSelectedRows((prev) =>
18 prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index]
19 );
20 };
21
22 return (
23 <div className="w-full border rounded-lg p-6">
24 <h3 className="text-sm font-semibold text-muted-foreground mb-3">
25 Hoverable & Selectable Rows
26 </h3>
27 <Table>
28 <TableHead>
29 <TableRow isHoverable={false}>
30 <TableHeaderCell>Product</TableHeaderCell>
31 <TableHeaderCell>Status</TableHeaderCell>
32 <TableHeaderCell align="right">Price</TableHeaderCell>
33 </TableRow>
34 </TableHead>
35 <TableBody>
36 {[
37 { id: 0, name: "Laptop", status: "In Stock", price: "$999" },
38 { id: 1, name: "Mouse", status: "In Stock", price: "$29" },
39 { id: 2, name: "Keyboard", status: "Low Stock", price: "$79" },
40 { id: 3, name: "Monitor", status: "Out of Stock", price: "$349" },
41 ].map((item) => (
42 <TableRow
43 key={item.id}
44 isSelected={selectedRows.includes(item.id)}
45 onClick={() => toggleRow(item.id)}
46 className="cursor-pointer"
47 >
48 <TableCell>{item.name}</TableCell>
49 <TableCell>{item.status}</TableCell>
50 <TableCell align="right">{item.price}</TableCell>
51 </TableRow>
52 ))}
53 </TableBody>
54 </Table>
55 <p className="text-xs text-muted-foreground mt-3">
56 Click rows to select them. {selectedRows.length} row(s) selected.
57 </p>
58 </div>
59 );
60}
61
62