数据展示
表格
语义化的 HTML 表格组件,用于展示结构化数据,支持表头、表体、表尾和标题。
默认
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| INV006 | Pending | Bank Transfer | $200.00 |
| INV007 | Unpaid | Credit Card | $300.00 |
| Total | $2,500.00 | ||
tsx
import { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@polyui/react/table"
export function TableDefault() {
return (
<Table>
<TableCaption>A list of your recent invoices.</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-25">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.invoice}>
<TableCell className="font-medium">{invoice.invoice}</TableCell>
<TableCell>{invoice.paymentStatus}</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">{invoice.totalAmount}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>Total</TableCell>
<TableCell className="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
)
}带边框
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| INV006 | Pending | Bank Transfer | $200.00 |
| INV007 | Unpaid | Credit Card | $300.00 |
| Total | $2,500.00 | ||
tsx
import { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@polyui/react/table"
export function TableBordered() {
return (
<Table className="border">
<TableCaption>Table with outer border.</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-25">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.invoice}>
<TableCell className="font-medium">{invoice.invoice}</TableCell>
<TableCell>{invoice.paymentStatus}</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">{invoice.totalAmount}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>Total</TableCell>
<TableCell className="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
)
}圆角
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| INV006 | Pending | Bank Transfer | $200.00 |
| INV007 | Unpaid | Credit Card | $300.00 |
| Total | $2,500.00 | ||
tsx
import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@polyui/react/table"
export function TableRounded() {
return (
<div className="w-full">
<div className="overflow-hidden rounded-md border">
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-25">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.invoice}>
<TableCell className="font-medium">{invoice.invoice}</TableCell>
<TableCell>{invoice.paymentStatus}</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">{invoice.totalAmount}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>Total</TableCell>
<TableCell className="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
</div>
</div>
)
}竖线
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| INV006 | Pending | Bank Transfer | $200.00 |
| INV007 | Unpaid | Credit Card | $300.00 |
| Total | $2,500.00 | ||
tsx
import { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@polyui/react/table"
export function TableVerticalLines() {
return (
<Table>
<TableCaption>Table with vertical column dividers.</TableCaption>
<TableHeader>
<TableRow className="*:border-border [&>:not(:last-child)]:border-r">
<TableHead className="w-25">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.invoice} className="*:border-border [&>:not(:last-child)]:border-r">
<TableCell className="font-medium">{invoice.invoice}</TableCell>
<TableCell>{invoice.paymentStatus}</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">{invoice.totalAmount}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>Total</TableCell>
<TableCell className="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
)
}无边框
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| INV006 | Pending | Bank Transfer | $200.00 |
| INV007 | Unpaid | Credit Card | $300.00 |
| Total | $2,500.00 | ||
tsx
import { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@polyui/react/table"
export function TableNoBorder() {
return (
<Table>
<TableCaption>Table without row borders.</TableCaption>
<TableHeader>
<TableRow className="bg-muted/50 border-none">
<TableHead className="w-25">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.invoice} className="border-none">
<TableCell className="font-medium">{invoice.invoice}</TableCell>
<TableCell>{invoice.paymentStatus}</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">{invoice.totalAmount}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter className="border-none">
<TableRow>
<TableCell colSpan={3}>Total</TableCell>
<TableCell className="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
)
}斑马纹行
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| INV006 | Pending | Bank Transfer | $200.00 |
| INV007 | Unpaid | Credit Card | $300.00 |
| Total | $2,500.00 | ||
tsx
import { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@polyui/react/table"
export function TableStripedRows() {
return (
<Table>
<TableCaption>Table with alternating row backgrounds.</TableCaption>
<TableHeader>
<TableRow className="hover:bg-transparent">
<TableHead className="w-25">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.invoice} className="odd:bg-muted/50 odd:hover:bg-muted/50 hover:bg-transparent">
<TableCell className="font-medium">{invoice.invoice}</TableCell>
<TableCell>{invoice.paymentStatus}</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">{invoice.totalAmount}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter className="bg-transparent">
<TableRow className="hover:bg-transparent">
<TableCell colSpan={3}>Total</TableCell>
<TableCell className="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
)
}斑马纹列
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| INV006 | Pending | Bank Transfer | $200.00 |
| INV007 | Unpaid | Credit Card | $300.00 |
| Total | $2,500.00 | ||
tsx
import { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@polyui/react/table"
export function TableStripedColumns() {
return (
<Table>
<TableCaption>Table with alternating column backgrounds.</TableCaption>
<TableHeader>
<TableRow className="[&_th]:even:bg-muted/50 hover:bg-transparent">
<TableHead className="w-25">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow key={invoice.invoice} className="[&_td]:even:bg-muted/50 hover:bg-transparent">
<TableCell className="font-medium">{invoice.invoice}</TableCell>
<TableCell>{invoice.paymentStatus}</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">{invoice.totalAmount}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter className="bg-transparent">
<TableRow className="hover:bg-transparent">
<TableCell colSpan={3}>Total</TableCell>
<TableCell className="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
)
}高亮行
| Invoice | Status | Method | Amount |
|---|---|---|---|
| INV001 | Paid | Credit Card | $250.00 |
| INV002 | Pending | PayPal | $150.00 |
| INV003 | Unpaid | Bank Transfer | $350.00 |
| INV004 | Paid | Credit Card | $450.00 |
| INV005 | Paid | PayPal | $550.00 |
| INV006 | Pending | Bank Transfer | $200.00 |
| INV007 | Unpaid | Credit Card | $300.00 |
| Total | $2,500.00 | ||
tsx
import { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@polyui/react/table"
export function TableHighlightedRow() {
return (
<Table>
<TableCaption>Table with a specific row highlighted.</TableCaption>
<TableHeader>
<TableRow>
<TableHead className="w-25">Invoice</TableHead>
<TableHead>Status</TableHead>
<TableHead>Method</TableHead>
<TableHead className="text-right">Amount</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{invoices.map((invoice) => (
<TableRow
key={invoice.invoice}
className="nth-3:bg-sky-600/10 nth-3:hover:bg-sky-600/20 nth-3:dark:bg-sky-400/10 nth-3:dark:hover:bg-sky-400/20"
>
<TableCell className="font-medium">{invoice.invoice}</TableCell>
<TableCell>{invoice.paymentStatus}</TableCell>
<TableCell>{invoice.paymentMethod}</TableCell>
<TableCell className="text-right">{invoice.totalAmount}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter>
<TableRow>
<TableCell colSpan={3}>Total</TableCell>
<TableCell className="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
)
}带头像
| Name | Location | Status | Balance | |
|---|---|---|---|---|
PG Philip George | philipgeorge20@gmail.com | Mumbai, India | Active | $10,696.00 |
TC Tiana Curtis | tiana12@yahoo.com | New York, US | Applied | $0.00 |
JD Jaylon Donin | jaylon23d.@outlook.com | Washington, US | Active | $569.00 |
KY Kim Yim | kim96@gmail.com | Busan, South Korea | Inactive | -$506.90 |
tsx
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@polyui/react/table"
import { Avatar, AvatarFallback, AvatarImage } from "@polyui/react/avatar"
export function TableWithAvatar() {
return (
<div className="w-full">
<div className="[&>div]:rounded-sm [&>div]:border">
<Table>
<TableHeader>
<TableRow className="hover:bg-transparent">
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead>Location</TableHead>
<TableHead>Status</TableHead>
<TableHead className="text-right">Balance</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{avatarItems.map((item) => (
<TableRow key={item.id}>
<TableCell>
<div className="flex items-center gap-3">
<Avatar>
<AvatarImage src={item.src} alt={item.fallback} />
<AvatarFallback className="text-xs">{item.fallback}</AvatarFallback>
</Avatar>
<div className="font-medium">{item.name}</div>
</div>
</TableCell>
<TableCell>{item.email}</TableCell>
<TableCell>{item.location}</TableCell>
<TableCell>{item.status}</TableCell>
<TableCell className="text-right">{item.balance}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
)
}可选行
| Name | Location | Status | Balance | ||
|---|---|---|---|---|---|
| Philip George | philipgeorge20@gmail.com | Mumbai, India | Active | $10,696.00 | |
| Sarah Chen | sarah.c@company.com | Singapore | Active | $600.00 | |
| James Wilson | j.wilson@company.com | London, UK | Inactive | $650.00 | |
| Maria Garcia | m.garcia@company.com | Madrid, Spain | Active | $0.00 | |
| David Kim | d.kim@company.com | Seoul, KR | Active | -$1,000.00 | |
| Total | $2,500.00 | ||||
tsx
import { Table, TableBody, TableCell, TableFooter, TableHead, TableHeader, TableRow } from "@polyui/react/table"
import { Checkbox } from "@polyui/react/checkbox"
export function TableSelectableRows() {
return (
<div className="w-full">
<div className="overflow-hidden rounded-md border">
<Table>
<TableHeader>
<TableRow className="hover:bg-transparent">
<TableHead>
<Checkbox aria-label="select-all" />
</TableHead>
<TableHead>Name</TableHead>
<TableHead>Email</TableHead>
<TableHead>Location</TableHead>
<TableHead>Status</TableHead>
<TableHead className="text-right">Balance</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{selectableItems.map((item) => (
<TableRow key={item.id} className="has-data-[state=checked]:bg-muted/50">
<TableCell>
<Checkbox aria-label={`select-${item.id}`} />
</TableCell>
<TableCell className="font-medium">{item.name}</TableCell>
<TableCell>{item.email}</TableCell>
<TableCell>{item.location}</TableCell>
<TableCell>{item.status}</TableCell>
<TableCell className="text-right">{item.balance}</TableCell>
</TableRow>
))}
</TableBody>
<TableFooter className="bg-transparent">
<TableRow className="hover:bg-transparent">
<TableCell colSpan={5}>Total</TableCell>
<TableCell className="text-right">$2,500.00</TableCell>
</TableRow>
</TableFooter>
</Table>
</div>
</div>
)
}固定列
| ID | Name | Occupation | Employer | Location | Last Access | Salary | |
|---|---|---|---|---|---|---|---|
| 1 | Alice Smith | Software Engineer | Alpha Tech | alice@example.com | United States | 12/16/2021 | $120,000 |
| 2 | Bob Johnson | Marketing Manager | Beta Corp | bob@example.com | Canada | 11/05/2021 | $100,000 |
| 3 | Charlie Brown | Graphic Designer | Gamma Studios | charlie@example.com | United Kingdom | 09/20/2022 | $75,000 |
| 4 | Dora Emily | HR Manager | Delta Corp | dora@example.com | Australia | 08/10/2020 | $40,000 |
| 5 | Ethan Hunt | Secret Agent | Eagle Eye | ethan@example.com | India | 11/20/2021 | $220,000 |
tsx
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@polyui/react/table"
export function TableStickyColumn() {
return (
<div className="w-full">
<div className="mx-auto max-w-2xl [&>div]:rounded-sm [&>div]:border">
<Table>
<TableHeader>
<TableRow className="hover:bg-transparent">
<TableHead className="bg-background sticky left-0">ID</TableHead>
<TableHead className="bg-background sticky left-7.5">Name</TableHead>
<TableHead>Occupation</TableHead>
<TableHead>Employer</TableHead>
<TableHead>Email</TableHead>
<TableHead>Location</TableHead>
<TableHead>Last Access</TableHead>
<TableHead>Salary</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{stickyData.map((row) => (
<TableRow key={row.id} className="hover:bg-transparent">
<TableCell className="bg-background sticky left-0 font-medium">{row.id}</TableCell>
<TableCell className="bg-background sticky left-7.5">{row.name}</TableCell>
<TableCell>{row.occupation}</TableCell>
<TableCell>{row.employer}</TableCell>
<TableCell>{row.email}</TableCell>
<TableCell>{row.location}</TableCell>
<TableCell>{row.lastaccess}</TableCell>
<TableCell>{row.salary}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
)
}垂直
| Product Name | Iphone 16 PRO |
| Serial Number | DF121543309KU |
| Category | Smartphone |
| Purchase Date | 15/06/2025 |
| Warranty Expiry | 15/06/2026 |
| Origin | China |
| Assign User | Alice Johnson |
| Value | $1,120.0 |
tsx
import { Table, TableBody, TableCell, TableRow } from "@polyui/react/table"
export function TableVertical() {
return (
<div className="mx-auto w-full max-w-lg">
<div className="overflow-hidden rounded-md border">
<Table>
<TableBody>
{[
["Product Name", "Iphone 16 PRO"],
["Serial Number", "DF121543309KU"],
["Category", "Smartphone"],
["Purchase Date", "15/06/2025"],
["Warranty Expiry", "15/06/2026"],
["Origin", "China"],
["Assign User", "Alice Johnson"],
["Value", "$1,120.0"],
].map(([label, value]) => (
<TableRow key={label} className="*:border-border [&>:not(:last-child)]:border-r">
<TableCell className="bg-muted/50 py-2 font-medium">{label}</TableCell>
<TableCell className="py-2">{value}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
)
}产品表格与操作
| Product | Color | Category | Price | Actions | |
|---|---|---|---|---|---|
WGC Chair Wooden Garden Chair | Black | Furniture | $269.09 | ||
J1R Nike Shoes Jordan 1 Retro OG | Red | Sneakers | $150.00 | ||
O7P OnePlus OnePlus 7 Pro | Nebula Blue | Smartphone | $869.00 | ||
NS Nintendo Nintendo Switch | Neon Blue and Red | Console Gaming | $499.00 | ||
AMM Apple Magic Mouse Apple Magic Mouse | Black | Electronics | $110.29 |
tsx
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@polyui/react/table"
import { Avatar, AvatarFallback, AvatarImage } from "@polyui/react/avatar"
import { Checkbox } from "@polyui/react/checkbox"
import { Button } from "@polyui/react/button"
import { ArchiveIcon, PencilIcon, Trash2Icon } from "lucide-react"
export function TableProductWithActions() {
return (
<div className="w-full">
<div className="[&>div]:rounded-sm [&>div]:border">
<Table>
<TableHeader>
<TableRow className="hover:bg-transparent">
<TableHead>
<Checkbox aria-label="select-all" />
</TableHead>
<TableHead>Product</TableHead>
<TableHead>Color</TableHead>
<TableHead>Category</TableHead>
<TableHead>Price</TableHead>
<TableHead className="w-0">Actions</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{productItems.map((item) => (
<TableRow key={item.id} className="has-data-[state=checked]:bg-muted/50">
<TableCell>
<Checkbox aria-label={`product-checkbox-${item.id}`} />
</TableCell>
<TableCell>
<div className="flex items-center gap-3">
<Avatar className="rounded-sm">
<AvatarImage src={item.src} alt={item.model} />
<AvatarFallback className="text-xs">{item.fallback}</AvatarFallback>
</Avatar>
<div>
<div className="font-medium">{item.productName}</div>
<span className="text-muted-foreground mt-0.5 text-xs">{item.model}</span>
</div>
</div>
</TableCell>
<TableCell>{item.color}</TableCell>
<TableCell>{item.category}</TableCell>
<TableCell>{item.price}</TableCell>
<TableCell className="flex items-center gap-1">
<Button variant="ghost" size="icon" className="rounded-full" aria-label={`product-${item.id}-edit`}>
<PencilIcon />
</Button>
<Button variant="ghost" size="icon" className="rounded-full" aria-label={`product-${item.id}-remove`}>
<Trash2Icon />
</Button>
<Button
variant="ghost"
size="icon"
className="rounded-full"
aria-label={`product-${item.id}-archive`}
>
<ArchiveIcon />
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</div>
</div>
)
}安装
bash
pnpm dlx shadcn@latest add table -c packages/reactProps
所有子组件均继承对应 HTML 元素的原生属性,并额外支持 className 进行样式覆盖。
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
className | string | — | 自定义样式类名,适用于所有子组件。 |
子组件
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
Table | React.ComponentProps<"table"> | — | 根容器,渲染 <table> |
TableHeader | React.ComponentProps<"thead"> | — | 表头区域 <thead> |
TableBody | React.ComponentProps<"tbody"> | — | 表体区域 <tbody> |
TableFooter | React.ComponentProps<"tfoot"> | — | 表尾区域 <tfoot> |
TableRow | React.ComponentProps<"tr"> | — | 表格行 <tr> |
TableHead | React.ComponentProps<"th"> | — | 表头单元格 <th> |
TableCell | React.ComponentProps<"td"> | — | 数据单元格 <td> |
TableCaption | React.ComponentProps<"caption"> | — | 表格标题 <caption> |