- Accordion
- Alert
- Avatar
- Badge
- Breadcrumb
- Button
- Button Group
- Calendarnew
- Card
- Carousel
- Checkbox
- Chip
- Collapse
- Dialog
- Drawer
- Footer
- Gallery
- Icon Button
- Image
- Input
- List
- Mapnew
- Menu
- Navbar
- Pagination
- Popover
- Progress
- Radio
- Rating
- Select
- Sidebar
- Skeletonnew
- Slider
- Software Purchase Card
- Sonner / Toastnew
- Speed Dial
- Spinner
- Stepper
- Switch
- Table
- Tabs
- Textarea
- Timeline
- Tooltip
- Typography
- Video
const TABLE_HEAD = ["Name", "Job", "Employed", ""]
const TABLE_ROWS = [
{
name: "John Michael",
job: "Manager",
date: "23/04/18",
},
{
name: "Alexa Liras",
job: "Developer",
date: "23/04/18",
},
{
name: "Laurent Perrier",
job: "Executive",
date: "19/09/17",
},
{
name: "Michael Levi",
job: "Developer",
date: "24/12/08",
},
{
name: "Richard Gran",
job: "Manager",
date: "04/10/21",
},
]
export function TableDemo() {
return (
<div className="border-border w-full overflow-hidden rounded-lg border">
<table className="w-full">
<thead className="border-border bg-muted border-b text-sm font-medium">
<tr>
{TABLE_HEAD.map((head) => (
<th key={head} className="px-2.5 py-2 text-start font-medium">
{head}
</th>
))}
</tr>
</thead>
<tbody className="text-sm">
{TABLE_ROWS.map(({ name, job, date }, index) => {
return (
<tr key={index} className="border-border border-b last:border-0">
<td className="p-3">{name}</td>
<td className="p-3">{job}</td>
<td className="p-3">{date}</td>
<td className="p-3">
<a
href="#"
className="text-primary text-sm font-medium hover:underline"
>
Edit
</a>
</td>
</tr>
)
})}
</tbody>
</table>
</div>
)
}
Installation
pnpm dlx @creative-tim/ui@latest add table
Usage
// Tables use standard HTML table elements
<table className="w-full">
<thead>
<tr>
<th>Column Header</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell Data</td>
</tr>
</tbody>
</table>Examples
Table with Striped Rows
Alternating row colors for improved readability of large datasets.
const TABLE_HEAD = ["Name", "Job", "Employed", ""]
const TABLE_ROWS = [
{
name: "John Michael",
job: "Manager",
date: "23/04/18",
},
{
name: "Alexa Liras",
job: "Developer",
date: "23/04/18",
},
{
name: "Laurent Perrier",
job: "Executive",
date: "19/09/17",
},
{
name: "Michael Levi",
job: "Developer",
date: "24/12/08",
},
{
name: "Richard Gran",
job: "Manager",
date: "04/10/21",
},
]
export function TableWithStripedRow() {
return (
<div className="border-border w-full overflow-hidden rounded-lg border">
<table className="w-full">
<thead className="border-border bg-muted border-b text-sm font-medium">
<tr>
{TABLE_HEAD.map((head) => (
<th key={head} className="px-2.5 py-2 text-start font-medium">
{head}
</th>
))}
</tr>
</thead>
<tbody className="text-sm">
{TABLE_ROWS.map(({ name, job, date }, index) => {
return (
<tr key={index} className="even:bg-muted">
<td className="p-3">{name}</td>
<td className="p-3">{job}</td>
<td className="p-3">{date}</td>
<td className="p-3">
<a
href="#"
className="text-primary text-sm font-medium hover:underline"
>
Edit
</a>
</td>
</tr>
)
})}
</tbody>
</table>
</div>
)
}
<tbody className="text-sm">
{TABLE_ROWS.map(({ name, job, date }, index) => (
<tr key={index} className="even:bg-muted">
<td className="p-3">{name}</td>
<td className="p-3">{job}</td>
<td className="p-3">{date}</td>
<td className="p-3">
<a
href="#"
className="text-primary text-sm font-medium hover:underline"
>
Edit
</a>
</td>
</tr>
))}
</tbody>Table with Striped Columns
Alternating column colors to visually separate data columns.
const TABLE_HEAD = ["Name", "Job", "Employed", ""]
const TABLE_ROWS = [
{
name: "John Michael",
job: "Manager",
date: "23/04/18",
},
{
name: "Alexa Liras",
job: "Developer",
date: "23/04/18",
},
{
name: "Laurent Perrier",
job: "Executive",
date: "19/09/17",
},
{
name: "Michael Levi",
job: "Developer",
date: "24/12/08",
},
{
name: "Richard Gran",
job: "Manager",
date: "04/10/21",
},
]
export function TableWithStripedColumn() {
return (
<div className="border-border w-full overflow-hidden rounded-lg border">
<table className="w-full">
<thead className="border-border bg-muted border-b text-sm font-medium">
<tr>
{TABLE_HEAD.map((head) => (
<th key={head} className="px-2.5 py-2 text-start font-medium">
{head}
</th>
))}
</tr>
</thead>
<tbody className="text-sm">
{TABLE_ROWS.map(({ name, job, date }, index) => {
const isLast = index === TABLE_ROWS.length - 1
const classes = isLast ? "p-3" : "p-3 border-b border-border"
return (
<tr key={index}>
<td className={classes}>{name}</td>
<td className={`${classes} bg-muted`}>{job}</td>
<td className={classes}>{date}</td>
<td className={`${classes} bg-muted`}>
<a
href="#"
className="text-primary text-sm font-medium hover:underline"
>
Edit
</a>
</td>
</tr>
)
})}
</tbody>
</table>
</div>
)
}
<tbody className="text-sm">
{TABLE_ROWS.map(({ name, job, date }, index) => {
const isLast = index === TABLE_ROWS.length - 1
const classes = isLast ? "p-3" : "p-3 border-b border-border"
return (
<tr key={index}>
<td className={classes}>{name}</td>
<td className={`${classes} bg-muted`}>{job}</td>
<td className={classes}>{date}</td>
<td className={`${classes} bg-muted`}>
<a
href="#"
className="text-primary text-sm font-medium hover:underline"
>
Edit
</a>
</td>
</tr>
)
})}
</tbody>Table Sortable
Interactive table with sortable columns for data organization.
Members list
See information about all members
Member | Function | Status | Employed | |
|---|---|---|---|---|
J John Michael[email protected] | ManagerOrganization | Online | 23/04/18 | |
A Alexa Liras[email protected] | ProgramatorDeveloper | Offline | 23/04/18 | |
L Laurent Perrier[email protected] | ExecutiveProjects | Offline | 19/09/17 | |
M Michael Levi[email protected] | ProgramatorDeveloper | Online | 24/12/08 | |
R Richard Gran[email protected] | ManagerExecutive | Offline | 04/10/21 |
"use client"
import * as React from "react"
import {
ArrowDown,
ArrowUp,
ArrowUpDown,
Pencil,
Search,
UserPlus,
} from "lucide-react"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
const TABS = [
{
label: "All",
value: "all",
},
{
label: "Monitored",
value: "monitored",
},
{
label: "Unmonitored",
value: "unmonitored",
},
]
const TABLE_HEAD = ["Member", "Function", "Status", "Employed", ""]
const TABLE_ROWS = [
{
img: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=100&h=100&fit=crop",
name: "John Michael",
email: "[email protected]",
job: "Manager",
org: "Organization",
online: true,
date: "23/04/18",
},
{
img: "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&h=100&fit=crop",
name: "Alexa Liras",
email: "[email protected]",
job: "Programator",
org: "Developer",
online: false,
date: "23/04/18",
},
{
img: "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=100&h=100&fit=crop",
name: "Laurent Perrier",
email: "[email protected]",
job: "Executive",
org: "Projects",
online: false,
date: "19/09/17",
},
{
img: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop",
name: "Michael Levi",
email: "[email protected]",
job: "Programator",
org: "Developer",
online: true,
date: "24/12/08",
},
{
img: "https://images.unsplash.com/photo-1519345182560-3f2917c472ef?w=100&h=100&fit=crop",
name: "Richard Gran",
email: "[email protected]",
job: "Manager",
org: "Executive",
online: false,
date: "04/10/21",
},
]
type SortKey = "name" | "job" | "status" | "date"
type SortDirection = "asc" | "desc" | null
export function TableSortable() {
const [sortKey, setSortKey] = React.useState<SortKey | null>(null)
const [sortDirection, setSortDirection] = React.useState<SortDirection>(null)
const handleSort = (key: SortKey) => {
if (sortKey === key) {
if (sortDirection === "asc") {
setSortDirection("desc")
} else if (sortDirection === "desc") {
setSortKey(null)
setSortDirection(null)
} else {
setSortDirection("asc")
}
} else {
setSortKey(key)
setSortDirection("asc")
}
}
const sortedRows = React.useMemo(() => {
if (!sortKey || !sortDirection) return TABLE_ROWS
return [...TABLE_ROWS].sort((a, b) => {
let aValue: string | boolean
let bValue: string | boolean
if (sortKey === "name") {
aValue = a.name
bValue = b.name
} else if (sortKey === "job") {
aValue = a.job
bValue = b.job
} else if (sortKey === "status") {
aValue = a.online
bValue = b.online
} else {
aValue = a.date
bValue = b.date
}
if (typeof aValue === "boolean" && typeof bValue === "boolean") {
return sortDirection === "asc"
? (aValue ? 1 : 0) - (bValue ? 1 : 0)
: (bValue ? 1 : 0) - (aValue ? 1 : 0)
}
if (typeof aValue === "string" && typeof bValue === "string") {
return sortDirection === "asc"
? aValue.localeCompare(bValue)
: bValue.localeCompare(aValue)
}
return 0
})
}, [sortKey, sortDirection])
const getSortIcon = (columnKey: SortKey) => {
if (sortKey !== columnKey) {
return <ArrowUpDown className="h-4 w-4" />
}
if (sortDirection === "asc") {
return <ArrowUp className="h-4 w-4" />
}
return <ArrowDown className="h-4 w-4" />
}
return (
<div className="w-full">
<div className="mb-8 flex items-center justify-between gap-8">
<div>
<h6 className="text-base font-semibold">Members list</h6>
<p className="text-muted-foreground mt-1 text-sm">
See information about all members
</p>
</div>
<div className="flex shrink-0 flex-col gap-2 sm:flex-row">
<Button variant="outline" size="sm">
View all
</Button>
<Button size="sm">
<UserPlus className="mr-2 h-4 w-4" />
Add member
</Button>
</div>
</div>
<div className="flex flex-col items-center justify-between gap-4 md:flex-row">
<Tabs defaultValue="all" className="w-full md:w-max">
<TabsList>
{TABS.map(({ label, value }) => (
<TabsTrigger key={value} value={value}>
{label}
</TabsTrigger>
))}
</TabsList>
</Tabs>
<div className="relative w-full md:w-72">
<Search className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2" />
<Input placeholder="Search" className="pl-9" />
</div>
</div>
<div className="border-border mt-4 w-full overflow-hidden rounded-lg border">
<table className="w-full">
<thead className="border-border bg-muted border-b text-sm font-medium">
<tr>
{TABLE_HEAD.map((head, index) => {
const sortKeys: (SortKey | null)[] = [
"name",
"job",
"status",
"date",
null,
]
const key = sortKeys[index]
return (
<th
key={head}
className={`px-2.5 py-2 text-start font-medium ${key ? "hover:bg-muted/80 cursor-pointer" : ""}`}
onClick={() => key && handleSort(key)}
>
<div className="text-muted-foreground flex items-center justify-between gap-2">
{head}
{key && getSortIcon(key)}
</div>
</th>
)
})}
</tr>
</thead>
<tbody className="text-sm">
{sortedRows.map(
({ img, name, email, job, org, online, date }, index) => {
return (
<tr
key={name}
className="border-border border-b last:border-0"
>
<td className="p-3">
<div className="flex items-center gap-3">
<Avatar className="h-9 w-9">
<AvatarImage src={img} alt={name} />
<AvatarFallback>{name.charAt(0)}</AvatarFallback>
</Avatar>
<div className="flex flex-col">
<span className="text-sm font-medium">{name}</span>
<span className="text-muted-foreground text-xs">
{email}
</span>
</div>
</div>
</td>
<td className="p-3">
<div className="flex flex-col">
<span className="text-sm font-medium">{job}</span>
<span className="text-muted-foreground text-xs">
{org}
</span>
</div>
</td>
<td className="p-3">
<Badge variant={online ? "default" : "secondary"}>
{online ? "Online" : "Offline"}
</Badge>
</td>
<td className="p-3">
<span className="text-sm">{date}</span>
</td>
<td className="p-3">
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon">
<Pencil className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Edit User</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</td>
</tr>
)
}
)}
</tbody>
</table>
</div>
<div className="border-border flex items-center justify-between border-t py-4">
<span className="text-muted-foreground text-sm">Page 1 of 10</span>
<div className="flex gap-2">
<Button variant="outline" size="sm">
Previous
</Button>
<Button variant="outline" size="sm">
Next
</Button>
</div>
</div>
</div>
)
}
import { ArrowUpDown, Pencil, Search, UserPlus } from "lucide-react"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
// Table with sorting indicators
;<thead className="border-border bg-muted border-b text-sm font-medium">
<tr>
{TABLE_HEAD.map((head, index) => (
<th
key={head}
className="cursor-pointer px-2.5 py-2 text-start font-medium"
>
<div className="text-muted-foreground flex items-center justify-between gap-2">
{head}
{index !== TABLE_HEAD.length - 1 && (
<ArrowUpDown className="h-4 w-4" />
)}
</div>
</th>
))}
</tr>
</thead>Table Members
Complete member management table with avatars, status badges, and actions.
Members list
See information about all members
| Member | Function | Status | Employed | |
|---|---|---|---|---|
J John Michael[email protected] | ManagerOrganization | Online | 23/04/18 | |
A Alexa Liras[email protected] | ProgramatorDeveloper | Offline | 23/04/18 | |
L Laurent Perrier[email protected] | ExecutiveProjects | Offline | 19/09/17 | |
M Michael Levi[email protected] | ProgramatorDeveloper | Online | 24/12/08 | |
R Richard Gran[email protected] | ManagerExecutive | Offline | 04/10/21 |
import { Pencil, Search, UserPlus } from "lucide-react"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
const TABS = [
{
label: "All",
value: "all",
},
{
label: "Monitored",
value: "monitored",
},
{
label: "Unmonitored",
value: "unmonitored",
},
]
const TABLE_HEAD = ["Member", "Function", "Status", "Employed", ""]
const TABLE_ROWS = [
{
img: "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?w=100&h=100&fit=crop",
name: "John Michael",
email: "[email protected]",
job: "Manager",
org: "Organization",
online: true,
date: "23/04/18",
},
{
img: "https://images.unsplash.com/photo-1494790108377-be9c29b29330?w=100&h=100&fit=crop",
name: "Alexa Liras",
email: "[email protected]",
job: "Programator",
org: "Developer",
online: false,
date: "23/04/18",
},
{
img: "https://images.unsplash.com/photo-1500648767791-00dcc994a43e?w=100&h=100&fit=crop",
name: "Laurent Perrier",
email: "[email protected]",
job: "Executive",
org: "Projects",
online: false,
date: "19/09/17",
},
{
img: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?w=100&h=100&fit=crop",
name: "Michael Levi",
email: "[email protected]",
job: "Programator",
org: "Developer",
online: true,
date: "24/12/08",
},
{
img: "https://images.unsplash.com/photo-1519345182560-3f2917c472ef?w=100&h=100&fit=crop",
name: "Richard Gran",
email: "[email protected]",
job: "Manager",
org: "Executive",
online: false,
date: "04/10/21",
},
]
export function TableMembers() {
return (
<div className="w-full">
<div className="mb-8 flex items-center justify-between gap-8">
<div>
<h6 className="text-base font-semibold">Members list</h6>
<p className="text-muted-foreground mt-1 text-sm">
See information about all members
</p>
</div>
<div className="flex shrink-0 flex-col gap-2 sm:flex-row">
<Button variant="outline" size="sm">
View all
</Button>
<Button size="sm">
<UserPlus className="mr-2 h-4 w-4" />
Add member
</Button>
</div>
</div>
<div className="flex flex-col items-center justify-between gap-4 md:flex-row">
<Tabs defaultValue="all" className="w-full md:w-max">
<TabsList>
{TABS.map(({ label, value }) => (
<TabsTrigger key={value} value={value}>
{label}
</TabsTrigger>
))}
</TabsList>
</Tabs>
<div className="relative w-full md:w-72">
<Search className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2" />
<Input placeholder="Search" className="pl-9" />
</div>
</div>
<div className="border-border mt-4 w-full overflow-hidden rounded-lg border">
<table className="w-full">
<thead className="border-border bg-muted border-b text-sm font-medium">
<tr>
{TABLE_HEAD.map((head) => (
<th key={head} className="px-2.5 py-2 text-start font-medium">
{head}
</th>
))}
</tr>
</thead>
<tbody className="text-sm">
{TABLE_ROWS.map(
({ img, name, email, job, org, online, date }, index) => {
return (
<tr
key={name}
className="border-border border-b last:border-0"
>
<td className="p-3">
<div className="flex items-center gap-3">
<Avatar className="h-9 w-9">
<AvatarImage src={img} alt={name} />
<AvatarFallback>{name.charAt(0)}</AvatarFallback>
</Avatar>
<div className="flex flex-col">
<span className="text-sm font-medium">{name}</span>
<span className="text-muted-foreground text-xs">
{email}
</span>
</div>
</div>
</td>
<td className="p-3">
<div className="flex flex-col">
<span className="text-sm font-medium">{job}</span>
<span className="text-muted-foreground text-xs">
{org}
</span>
</div>
</td>
<td className="p-3">
<Badge variant={online ? "default" : "secondary"}>
{online ? "Online" : "Offline"}
</Badge>
</td>
<td className="p-3">
<span className="text-sm">{date}</span>
</td>
<td className="p-3">
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon">
<Pencil className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Edit User</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</td>
</tr>
)
}
)}
</tbody>
</table>
</div>
<div className="border-border flex items-center justify-between border-t py-4">
<span className="text-muted-foreground text-sm">Page 1 of 10</span>
<div className="flex gap-2">
<Button variant="outline" size="sm">
Previous
</Button>
<Button variant="outline" size="sm">
Next
</Button>
</div>
</div>
</div>
)
}
import { Pencil, UserPlus, Search } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
// Member row with avatar and status
<td className="p-3">
<div className="flex items-center gap-3">
<Avatar className="h-9 w-9">
<AvatarImage src={img} alt={name} />
<AvatarFallback>{name.charAt(0)}</AvatarFallback>
</Avatar>
<div className="flex flex-col">
<span className="text-sm font-medium">{name}</span>
<span className="text-xs text-muted-foreground">{email}</span>
</div>
</div>
</td>
<td className="p-3">
<Badge variant={online ? "default" : "secondary"}>
{online ? "Online" : "Offline"}
</Badge>
</td>Table Transactions
Detailed transaction table with logos, status badges, and pagination.
Recent Transactions
These are details about the last transactions
| Transaction | Amount | Date | Status | Account | |
|---|---|---|---|---|---|
SSpotify | $2,500 | Wed 3:00pm | paid | V visa 123406/2026 | |
AAmazon | $5,000 | Wed 1:00pm | paid | M master card 123406/2026 | |
PPinterest | $3,400 | Mon 7:40pm | pending | M master card 123406/2026 | |
GGoogle | $1,000 | Wed 5:00pm | paid | V visa 123406/2026 | |
nnetflix | $14,000 | Wed 3:30am | cancelled | V visa 123406/2026 |
import { Download, Pencil, Search } from "lucide-react"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip"
const TABLE_HEAD = ["Transaction", "Amount", "Date", "Status", "Account", ""]
const TABLE_ROWS = [
{
img: "https://docs.material-tailwind.com/img/logos/logo-spotify.svg",
name: "Spotify",
amount: "$2,500",
date: "Wed 3:00pm",
status: "paid",
account: "visa",
accountNumber: "1234",
expiry: "06/2026",
},
{
img: "https://docs.material-tailwind.com/img/logos/logo-amazon.svg",
name: "Amazon",
amount: "$5,000",
date: "Wed 1:00pm",
status: "paid",
account: "master-card",
accountNumber: "1234",
expiry: "06/2026",
},
{
img: "https://docs.material-tailwind.com/img/logos/logo-pinterest.svg",
name: "Pinterest",
amount: "$3,400",
date: "Mon 7:40pm",
status: "pending",
account: "master-card",
accountNumber: "1234",
expiry: "06/2026",
},
{
img: "https://docs.material-tailwind.com/img/logos/logo-google.svg",
name: "Google",
amount: "$1,000",
date: "Wed 5:00pm",
status: "paid",
account: "visa",
accountNumber: "1234",
expiry: "06/2026",
},
{
img: "https://docs.material-tailwind.com/img/logos/logo-netflix.svg",
name: "netflix",
amount: "$14,000",
date: "Wed 3:30am",
status: "cancelled",
account: "visa",
accountNumber: "1234",
expiry: "06/2026",
},
]
export function TableTransactions() {
return (
<div className="w-full px-2">
<div className="mb-4 flex flex-col justify-between gap-8 md:flex-row md:items-center">
<div>
<h6 className="text-base font-semibold">Recent Transactions</h6>
<p className="text-muted-foreground mt-1 text-sm">
These are details about the last transactions
</p>
</div>
<div className="flex w-full shrink-0 gap-2 md:w-max">
<div className="relative w-full md:w-72">
<Search className="text-muted-foreground absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2" />
<Input placeholder="Search" className="pl-9" />
</div>
<Button size="sm">
<Download className="mr-2 h-4 w-4" />
Download
</Button>
</div>
</div>
<div className="border-border w-full overflow-hidden rounded-lg border">
<table className="w-full text-left">
<thead className="border-border bg-muted border-b text-sm font-medium">
<tr>
{TABLE_HEAD.map((head) => (
<th key={head} className="px-2.5 py-2 text-start font-medium">
{head}
</th>
))}
</tr>
</thead>
<tbody>
{TABLE_ROWS.map(
(
{
img,
name,
amount,
date,
status,
account,
accountNumber,
expiry,
},
index
) => {
const isLast = index === TABLE_ROWS.length - 1
const classes = isLast ? "p-4" : "p-4 border-b border-border"
return (
<tr key={name}>
<td className={classes}>
<div className="flex items-center gap-3">
<Avatar className="border-border bg-muted h-10 w-10 rounded-md border p-1">
<AvatarImage
src={img}
alt={name}
className="object-contain"
/>
<AvatarFallback>{name.charAt(0)}</AvatarFallback>
</Avatar>
<span className="text-sm font-bold">{name}</span>
</div>
</td>
<td className={classes}>
<span className="text-sm">{amount}</span>
</td>
<td className={classes}>
<span className="text-sm">{date}</span>
</td>
<td className={classes}>
<Badge
variant={
status === "paid"
? "default"
: status === "pending"
? "secondary"
: "destructive"
}
>
{status}
</Badge>
</td>
<td className={classes}>
<div className="flex items-center gap-3">
<div className="border-border h-9 w-12 rounded-md border p-1">
<Avatar className="h-full w-full rounded-none">
<AvatarImage
src={
account === "visa"
? "https://demos.creative-tim.com/test/corporate-ui-dashboard/assets/img/logos/visa.png"
: "https://demos.creative-tim.com/test/corporate-ui-dashboard/assets/img/logos/mastercard.png"
}
alt={account}
className="h-full w-full object-contain p-1"
/>
<AvatarFallback className="rounded-none">
{account.charAt(0).toUpperCase()}
</AvatarFallback>
</Avatar>
</div>
<div className="flex flex-col">
<span className="text-sm capitalize">
{account.split("-").join(" ")} {accountNumber}
</span>
<span className="text-muted-foreground text-xs">
{expiry}
</span>
</div>
</div>
</td>
<td className={classes}>
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon">
<Pencil className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Edit User</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</td>
</tr>
)
}
)}
</tbody>
</table>
</div>
<div className="border-border flex items-center justify-between border-t py-4">
<Button variant="outline" size="sm">
Previous
</Button>
<div className="flex items-center gap-2">
<Button size="sm" variant="default">
1
</Button>
<Button variant="ghost" size="sm">
2
</Button>
<Button variant="ghost" size="sm">
3
</Button>
<Button variant="ghost" size="sm">
...
</Button>
<Button variant="ghost" size="sm">
8
</Button>
<Button variant="ghost" size="sm">
9
</Button>
<Button variant="ghost" size="sm">
10
</Button>
</div>
<Button variant="outline" size="sm">
Next
</Button>
</div>
</div>
)
}
import { Download, Search, Pencil } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
// Transaction row with company logo and payment method
<td className={classes}>
<div className="flex items-center gap-3">
<Avatar className="h-10 w-10 rounded-md border border-border bg-muted p-1">
<AvatarImage src={img} alt={name} className="object-contain" />
<AvatarFallback>{name.charAt(0)}</AvatarFallback>
</Avatar>
<span className="text-sm font-bold">{name}</span>
</div>
</td>
<td className={classes}>
<Badge variant={
status === "paid" ? "default" : status === "pending" ? "secondary" : "destructive"
}>
{status}
</Badge>
</td>Table Structure
Tables are built using standard HTML table elements with Tailwind CSS classes for styling:
Table Container
overflow-hidden rounded-lg border border-border- Container styling with rounded corners and borderw-full- Full width table
Table Header
thead- Table header sectionborder-b border-border bg-muted- Header styling with bottom border and muted backgroundtext-sm font-medium- Typography for header cells
Table Body
tbody- Table body sectiontext-sm- Typography for body cellsborder-b border-border last:border-0- Row borders (no border on last row)
Table Cells
th- Header cells withtext-startfor left alignmenttd- Data cells withp-3for padding- Use
classNamefor conditional styling
Props and Customization
Table Variants
Basic Table
- Simple table structure with borders and headers
- Use for straightforward data display
Striped Rows
- Add
even:bg-mutedto<tr>elements - Improves readability for long lists
Striped Columns
- Add
bg-mutedto specific<td>elements - Visually separates columns
Interactive Tables
- Combine with Button, Input, Badge, Avatar components
- Add sorting, filtering, and actions
- Include tooltips for better UX
Styling
Tables support all standard Tailwind CSS classes:
- Border:
border,border-border,border-b - Background:
bg-muted,bg-card, custom colors - Spacing:
p-3,px-2.5 py-2,gap-3 - Typography:
text-sm,text-xs,font-medium,font-bold - States:
hover:,even:,last:,cursor-pointer
Responsive Design
Make tables responsive with horizontal scrolling:
<div className="w-full overflow-x-auto">
<table className="min-w-full">{/* table content */}</table>
</div>For mobile-friendly tables, consider using card layouts or hiding less important columns.