Table Component

Tables display information in a structured grid format, making it easy to scan, compare, and analyze data.

Basic Table

NameEmailRoleStatus
John Doejohn@example.comAdminActive
Jane Smithjane@example.comEditorInactive
Mike Johnsonmike@example.comViewerPending
Sara Williamssara@example.comEditorActive
Robert Brownrobert@example.comAdminActive
Code Example
<Table className="border rounded-lg overflow-hidden">
  <TableHeader>
    <TableRow>
      <TableHead>Name</TableHead>
      <TableHead>Email</TableHead>
      <TableHead>Role</TableHead>
      <TableHead>Status</TableHead>
    </TableRow>
  </TableHeader>
  <TableBody>
    {data.map((row) => (
      <TableRow key={row.id}>
        <TableCell>{row.name}</TableCell>
        <TableCell>{row.email}</TableCell>
        <TableCell>{row.role}</TableCell>
        <TableCell>{row.status}</TableCell>
      </TableRow>
    ))}
  </TableBody>
</Table>

With Sortable Columns

Name
Email
RoleStatus
John Doejohn@example.comAdminActive
Jane Smithjane@example.comEditorInactive
Mike Johnsonmike@example.comViewerPending
Sara Williamssara@example.comEditorActive
Robert Brownrobert@example.comAdminActive
Code Example
const [sortDirection, setSortDirection] = useState<'asc' | 'desc' | null>(null)
const [sortColumn, setSortColumn] = useState<string | null>(null)

const handleSort = (column: string) => {
  if (sortColumn === column) {
    if (sortDirection === 'asc') {
      setSortDirection('desc')
    } else if (sortDirection === 'desc') {
      setSortDirection(null)
      setSortColumn(null)
    } else {
      setSortDirection('asc')
    }
  } else {
    setSortColumn(column)
    setSortDirection('asc')
  }
}

<TableHead 
  className="cursor-pointer"
  onClick={() => handleSort('name')}
>
  <div className="flex items-center">
    Name
    {sortColumn === 'name' && (
      sortDirection === 'asc' ? 
        <ChevronUp className="ml-1 h-4 w-4" /> : 
        <ChevronDown className="ml-1 h-4 w-4" />
    )}
  </div>
</TableHead>

With Selection

NameEmailRoleStatus
John Doejohn@example.comAdminActive
Jane Smithjane@example.comEditorInactive
Mike Johnsonmike@example.comViewerPending
Sara Williamssara@example.comEditorActive
Robert Brownrobert@example.comAdminActive
Code Example
const [selectedRows, setSelectedRows] = useState<Record<number, boolean>>({})

const toggleSelectAll = (checked: boolean) => {
  if (checked) {
    const newSelected: Record<number, boolean> = {}
    data.forEach((row, index) => {
      newSelected[index] = true
    })
    setSelectedRows(newSelected)
  } else {
    setSelectedRows({})
  }
}

const toggleSelectRow = (index: number) => {
  setSelectedRows(prev => ({
    ...prev,
    [index]: !prev[index]
  }))
}

const areAllSelected = data.length > 0 && 
  Object.keys(selectedRows).length === data.length && 
  Object.values(selectedRows).every(Boolean)

<TableHead className="w-[50px]">
  <Checkbox
    checked={areAllSelected}
    onCheckedChange={toggleSelectAll}
  />
</TableHead>

<TableCell>
  <Checkbox
    checked={selectedRows[index] || false}
    onCheckedChange={() => toggleSelectRow(index)}
  />
</TableCell>

With Actions and Status Badge

NameEmailRoleStatusActions
John Doejohn@example.comAdmin
Active
Jane Smithjane@example.comEditor
Inactive
Mike Johnsonmike@example.comViewer
Pending
Sara Williamssara@example.comEditor
Active
Robert Brownrobert@example.comAdmin
Active
Code Example
<TableCell>
  <Badge 
    variant={
      row.status === 'Active' ? 'success' : 
      row.status === 'Inactive' ? 'destructive' : 
      'warning'
    }
  >
    {row.status}
  </Badge>
</TableCell>
<TableCell className="text-right">
  <div className="flex justify-end items-center gap-2">
    <Button variant="ghost" size="icon" className="h-8 w-8">
      <Edit className="h-4 w-4" />
    </Button>
    <Button variant="ghost" size="icon" className="h-8 w-8 text-red-500">
      <Trash className="h-4 w-4" />
    </Button>
    <Button variant="ghost" size="icon" className="h-8 w-8">
      <MoreHorizontal className="h-4 w-4" />
    </Button>
  </div>
</TableCell>

Usage Guidelines

Here are some best practices for using tables:

  • Use tables when you need to present structured data with multiple attributes
  • Keep tables simple by only including necessary columns
  • Provide clear column headers to help users understand the data
  • Use visual cues like badges or icons to highlight status or special conditions
  • Include actions when users need to manipulate individual records
  • Add sorting, filtering, or pagination for large datasets
  • Use selection when users need to perform bulk actions on multiple rows
  • Ensure tables are responsive and accessible on different screen sizes