Table

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.

NameEmailStatus
Sarah Johnsonsarah@example.comActive
Michael Chenmichael@example.comActive
Emily Rodriguezemily@example.comInactive
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
46

Installation

Run the following command to add the component:

npx cx add table

Sizes

Sm - Compact

NameEmailStatus
Sarah Johnsonsarah@example.comActive
Michael Chenmichael@example.comActive
Emily Rodriguezemily@example.comInactive

Md - Default

NameEmailStatus
Sarah Johnsonsarah@example.comActive
Michael Chenmichael@example.comActive
Emily Rodriguezemily@example.comInactive

Lg - Spacious

NameEmailStatus
Sarah Johnsonsarah@example.comActive
Michael Chenmichael@example.comActive
Emily Rodriguezemily@example.comInactive
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

Text Alignment

Left Alignment

NameEmailStatus
Sarah Johnsonsarah@example.comActive
Michael Chenmichael@example.comActive
Emily Rodriguezemily@example.comInactive

Center Alignment

NameEmailStatus
Sarah Johnsonsarah@example.comActive
Michael Chenmichael@example.comActive
Emily Rodriguezemily@example.comInactive

Right Alignment

NameEmailStatus
Sarah Johnsonsarah@example.comActive
Michael Chenmichael@example.comActive
Emily Rodriguezemily@example.comInactive
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

Interactive States

Hoverable & Selectable Rows

ProductStatusPrice
LaptopIn Stock$999
MouseIn Stock$29
KeyboardLow Stock$79
MonitorOut 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