Skip to main content
Location: sabo/src/components/dashboard/data-table.tsx
The actual implementation uses @tanstack/react-table + @dnd-kit for advanced features (sorting, filtering, drag-drop). See the file for full example.

When to use

  • Present datasets with sorting, filtering, pagination in the dashboard context.

Usage

// Pattern: table toolbar + UI Table primitives
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell } from "@/components/ui/table";

const rows = [{ id: 1, name: "Jane", role: "Admin" }];

export function ExampleTable() {
  return (
    <div className="space-y-3">
      {/* Optional toolbar (filters/actions) */}
      <div className="flex items-center justify-between gap-2">
        <div className="text-sm text-muted-foreground">1 result</div>
      </div>
      <Table>
        <TableHeader>
          <TableRow>
            <TableHead>Name</TableHead>
            <TableHead>Role</TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          {rows.map((r) => (
            <TableRow key={r.id}>
              <TableCell>{r.name}</TableCell>
              <TableCell>{r.role}</TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </div>
  );
}

Styling tip

  • Keep columns minimal; move heavy controls to toolbar or row actions.

Key features

The actual data-table.tsx implementation includes:
  • @tanstack/react-table: Column sorting, filtering, pagination
  • @dnd-kit: Drag-and-drop row reordering
  • Toolbar: Search, filters, and column visibility toggles
  • Responsive: Horizontal scroll on overflow
The component is a complex example. Review sabo/src/components/dashboard/data-table.tsx for the full implementation with TanStack Table and DnD Kit.

Steps

1

Define columns

Start with 2–4 key columns. Use truncate for long text.
<TableHead className="w-[100px]">ID</TableHead>
<TableHead>Name</TableHead>
<TableHead className="text-right">Amount</TableHead>
2

Add sorting/filtering

For simple tables, implement client-side sorting with Array.sort(). For large datasets, use TanStack Table with server-side pagination.
Place filters in a toolbar above the table. Avoid cramming controls into header cells.
<div className="flex items-center gap-2 mb-4">
  <Input placeholder="Search..." onChange={handleSearch} />
  <Select onValueChange={handleFilter}>
    <SelectTrigger>Filter</SelectTrigger>
    <SelectContent>
      <SelectItem value="all">All</SelectItem>
      <SelectItem value="active">Active</SelectItem>
    </SelectContent>
  </Select>
</div>
3

Row actions

Add a compact actions column with a dropdown menu for edit/delete/view:
<TableCell className="text-right">
  <DropdownMenu>
    <DropdownMenuTrigger asChild>
      <Button variant="ghost" size="icon">
        <MoreHorizontal className="h-4 w-4" />
      </Button>
    </DropdownMenuTrigger>
    <DropdownMenuContent align="end">
      <DropdownMenuItem onClick={() => handleEdit(row.id)}>Edit</DropdownMenuItem>
      <DropdownMenuItem onClick={() => handleDelete(row.id)}>Delete</DropdownMenuItem>
    </DropdownMenuContent>
  </DropdownMenu>
</TableCell>

Troubleshooting

  • Table overflowing viewport
    • Wrap <Table> in a div with overflow-x-auto
  • Sorting not working
    • Ensure useState for sort state and Array.sort() callback are wired correctly
  • DnD conflicts with click events
    • Use event stopPropagation in row click handlers