Skip to main content
PolyUI/docs

数据展示

表格

语义化的 HTML 表格组件,用于展示结构化数据,支持表头、表体、表尾和标题。

默认

A list of your recent invoices.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
INV003UnpaidBank Transfer$350.00
INV004PaidCredit Card$450.00
INV005PaidPayPal$550.00
INV006PendingBank Transfer$200.00
INV007UnpaidCredit 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>
  )
}

带边框

Table with outer border.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
INV003UnpaidBank Transfer$350.00
INV004PaidCredit Card$450.00
INV005PaidPayPal$550.00
INV006PendingBank Transfer$200.00
INV007UnpaidCredit 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>
  )
}

圆角

InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
INV003UnpaidBank Transfer$350.00
INV004PaidCredit Card$450.00
INV005PaidPayPal$550.00
INV006PendingBank Transfer$200.00
INV007UnpaidCredit 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>
  )
}

竖线

Table with vertical column dividers.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
INV003UnpaidBank Transfer$350.00
INV004PaidCredit Card$450.00
INV005PaidPayPal$550.00
INV006PendingBank Transfer$200.00
INV007UnpaidCredit 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>
  )
}

无边框

Table without row borders.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
INV003UnpaidBank Transfer$350.00
INV004PaidCredit Card$450.00
INV005PaidPayPal$550.00
INV006PendingBank Transfer$200.00
INV007UnpaidCredit 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>
  )
}

斑马纹行

Table with alternating row backgrounds.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
INV003UnpaidBank Transfer$350.00
INV004PaidCredit Card$450.00
INV005PaidPayPal$550.00
INV006PendingBank Transfer$200.00
INV007UnpaidCredit 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>
  )
}

斑马纹列

Table with alternating column backgrounds.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
INV003UnpaidBank Transfer$350.00
INV004PaidCredit Card$450.00
INV005PaidPayPal$550.00
INV006PendingBank Transfer$200.00
INV007UnpaidCredit 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>
  )
}

高亮行

Table with a specific row highlighted.
InvoiceStatusMethodAmount
INV001PaidCredit Card$250.00
INV002PendingPayPal$150.00
INV003UnpaidBank Transfer$350.00
INV004PaidCredit Card$450.00
INV005PaidPayPal$550.00
INV006PendingBank Transfer$200.00
INV007UnpaidCredit 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>
  )
}

带头像

NameEmailLocationStatusBalance
PG
Philip George
philipgeorge20@gmail.comMumbai, IndiaActive$10,696.00
TC
Tiana Curtis
tiana12@yahoo.comNew York, USApplied$0.00
JD
Jaylon Donin
jaylon23d.@outlook.comWashington, USActive$569.00
KY
Kim Yim
kim96@gmail.comBusan, South KoreaInactive-$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>
  )
}

可选行

NameEmailLocationStatusBalance
Philip Georgephilipgeorge20@gmail.comMumbai, IndiaActive$10,696.00
Sarah Chensarah.c@company.comSingaporeActive$600.00
James Wilsonj.wilson@company.comLondon, UKInactive$650.00
Maria Garciam.garcia@company.comMadrid, SpainActive$0.00
David Kimd.kim@company.comSeoul, KRActive-$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>
  )
}

固定列

IDNameOccupationEmployerEmailLocationLast AccessSalary
1Alice SmithSoftware EngineerAlpha Techalice@example.comUnited States12/16/2021$120,000
2Bob JohnsonMarketing ManagerBeta Corpbob@example.comCanada11/05/2021$100,000
3Charlie BrownGraphic DesignerGamma Studioscharlie@example.comUnited Kingdom09/20/2022$75,000
4Dora EmilyHR ManagerDelta Corpdora@example.comAustralia08/10/2020$40,000
5Ethan HuntSecret AgentEagle Eyeethan@example.comIndia11/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 NameIphone 16 PRO
Serial NumberDF121543309KU
CategorySmartphone
Purchase Date15/06/2025
Warranty Expiry15/06/2026
OriginChina
Assign UserAlice 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>
  )
}

产品表格与操作

ProductColorCategoryPriceActions
WGC
Chair
Wooden Garden Chair
BlackFurniture$269.09
J1R
Nike Shoes
Jordan 1 Retro OG
RedSneakers$150.00
O7P
OnePlus
OnePlus 7 Pro
Nebula BlueSmartphone$869.00
NS
Nintendo
Nintendo Switch
Neon Blue and RedConsole Gaming$499.00
AMM
Apple Magic Mouse
Apple Magic Mouse
BlackElectronics$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/react

Props

所有子组件均继承对应 HTML 元素的原生属性,并额外支持 className 进行样式覆盖。

属性类型默认值说明
classNamestring自定义样式类名,适用于所有子组件。

子组件

属性类型默认值说明
TableReact.ComponentProps<"table">根容器,渲染 <table>
TableHeaderReact.ComponentProps<"thead">表头区域 <thead>
TableBodyReact.ComponentProps<"tbody">表体区域 <tbody>
TableFooterReact.ComponentProps<"tfoot">表尾区域 <tfoot>
TableRowReact.ComponentProps<"tr">表格行 <tr>
TableHeadReact.ComponentProps<"th">表头单元格 <th>
TableCellReact.ComponentProps<"td">数据单元格 <td>
TableCaptionReact.ComponentProps<"caption">表格标题 <caption>