Table Component
Tables display information in a structured grid format, making it easy to scan, compare, and analyze data.
Basic Table
| Name | Role | Status | |
|---|---|---|---|
| John Doe | john@example.com | Admin | Active |
| Jane Smith | jane@example.com | Editor | Inactive |
| Mike Johnson | mike@example.com | Viewer | Pending |
| Sara Williams | sara@example.com | Editor | Active |
| Robert Brown | robert@example.com | Admin | Active |
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 | Role | Status |
|---|---|---|---|
| John Doe | john@example.com | Admin | Active |
| Jane Smith | jane@example.com | Editor | Inactive |
| Mike Johnson | mike@example.com | Viewer | Pending |
| Sara Williams | sara@example.com | Editor | Active |
| Robert Brown | robert@example.com | Admin | Active |
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
| Name | Role | Status | ||
|---|---|---|---|---|
| John Doe | john@example.com | Admin | Active | |
| Jane Smith | jane@example.com | Editor | Inactive | |
| Mike Johnson | mike@example.com | Viewer | Pending | |
| Sara Williams | sara@example.com | Editor | Active | |
| Robert Brown | robert@example.com | Admin | Active |
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
| Name | Role | Status | Actions | |
|---|---|---|---|---|
| John Doe | john@example.com | Admin | Active | |
| Jane Smith | jane@example.com | Editor | Inactive | |
| Mike Johnson | mike@example.com | Viewer | Pending | |
| Sara Williams | sara@example.com | Editor | Active | |
| Robert Brown | robert@example.com | Admin | 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