- Gallery
- Data Display
- DataTable
New
DataTable
Advanced table with sortable headers, alternating rows, and status badges
Data Displaytablesortabledatagrid
Dependencies
shadcn/ui components needed:
npx shadcn@latest add cardnpx shadcn@latest add badgenpx shadcn@latest add tableHow to use this component
Copy the code below into your project. Make sure you have the required shadcn/ui dependencies installed. Then import and use the component in your pages or layouts.
Code
1"use client"23import * as React from "react"4import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"5import { Badge } from "@/components/ui/badge"6import {7 Table,8 TableBody,9 TableCell,10 TableHead,11 TableHeader,12 TableRow,13} from "@/components/ui/table"14import { cn } from "@/lib/utils"1516interface DataTableProps {17 className?: string18}1920type SortDirection = "asc" | "desc" | null2122interface Column {23 key: string24 label: string25 sortable: boolean26}2728interface Row {29 id: string30 name: string31 status: "active" | "inactive" | "pending"32 role: string33 email: string34 lastActive: string35}3637const statusVariants = {38 active: "bg-emerald-500/10 text-emerald-600 border-emerald-200 hover:bg-emerald-500/20",39 inactive: "bg-red-500/10 text-red-600 border-red-200 hover:bg-red-500/20",40 pending: "bg-amber-500/10 text-amber-600 border-amber-200 hover:bg-amber-500/20",41}4243export function DataTable({ className }: DataTableProps) {44 const [sortColumn, setSortColumn] = React.useState<string | null>(null)45 const [sortDirection, setSortDirection] = React.useState<SortDirection>(null)4647 const columns: Column[] = [48 { key: "name", label: "Name", sortable: true },49 { key: "status", label: "Status", sortable: true },50 { key: "role", label: "Role", sortable: true },51 { key: "email", label: "Email", sortable: true },52 { key: "lastActive", label: "Last Active", sortable: true },53 ]5455 const [rows, setRows] = React.useState<Row[]>([56 { id: "1", name: "Sarah Chen", status: "active", role: "Designer", email: "sarah@example.com", lastActive: "2 min ago" },57 { id: "2", name: "Alex Rivera", status: "active", role: "Developer", email: "alex@example.com", lastActive: "15 min ago" },58 { id: "3", name: "Jordan Lee", status: "pending", role: "Manager", email: "jordan@example.com", lastActive: "1 hour ago" },59 { id: "4", name: "Morgan Smith", status: "inactive", role: "Analyst", email: "morgan@example.com", lastActive: "3 days ago" },60 { id: "5", name: "Taylor Kim", status: "active", role: "Engineer", email: "taylor@example.com", lastActive: "5 min ago" },61 { id: "6", name: "Casey Brown", status: "pending", role: "Designer", email: "casey@example.com", lastActive: "2 hours ago" },62 ])6364 const handleSort = (key: string) => {65 if (sortColumn === key) {66 if (sortDirection === "asc") {67 setSortDirection("desc")68 } else if (sortDirection === "desc") {69 setSortColumn(null)70 setSortDirection(null)71 } else {72 setSortDirection("asc")73 }74 } else {75 setSortColumn(key)76 setSortDirection("asc")77 }7879 if (sortColumn === key && sortDirection === null) {80 setRows(rows.slice().reverse())81 } else {82 const sorted = [...rows].sort((a, b) => {83 const aVal = a[key as keyof Row]84 const bVal = b[key as keyof Row]85 if (sortDirection === "asc") {86 return aVal > bVal ? 1 : -187 }88 return aVal < bVal ? 1 : -189 })90 setRows(sorted)91 }92 }9394 return (95 <Card className={cn("w-full", className)}>96 <CardHeader>97 <CardTitle>Team Members</CardTitle>98 </CardHeader>99 <CardContent>100 <Table>101 <TableHeader>102 <TableRow>103 {columns.map((col) => (104 <TableHead key={col.key}>105 {col.sortable ? (106 <button107 onClick={() => handleSort(col.key)}108 className="flex items-center gap-1 hover:text-primary transition-colors font-medium"109 >110 {col.label}111 {sortColumn === col.key && (112 <span className="text-xs">113 {sortDirection === "asc" ? "▲" : sortDirection === "desc" ? "▼" : ""}114 </span>115 )}116 </button>117 ) : (118 col.label119 )}120 </TableHead>121 ))}122 </TableRow>123 </TableHeader>124 <TableBody>125 {rows.map((row, i) => (126 <TableRow key={row.id} className={cn("hover:bg-muted/50 transition-colors", i % 2 === 0 && "bg-muted/20")}>127 <TableCell className="font-medium">{row.name}</TableCell>128 <TableCell>129 <Badge variant="outline" className={cn("text-xs", statusVariants[row.status])}>130 {row.status}131 </Badge>132 </TableCell>133 <TableCell>{row.role}</TableCell>134 <TableCell className="text-muted-foreground">{row.email}</TableCell>135 <TableCell className="text-muted-foreground">{row.lastActive}</TableCell>136 </TableRow>137 ))}138 </TableBody>139 </Table>140 </CardContent>141 </Card>142 )143}