Skip to content
Lenso UI

Table 表格

表格以行和列展示结构化数据,支持排序、选择、列宽调整与无限滚动。

用法

import { Table } from '@lenso/ui';

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";
// Adapted from HeroUI v3.2.6 table-basic (Apache-2.0).import * as stylex from "@stylexjs/stylex";import { Table } from "@lenso/ui";
const rows = [  { key: "kate", name: "Kate Moore", role: "CEO", status: "Active", email: "[email protected]" },  { key: "john", name: "John Smith", role: "CTO", status: "Active", email: "[email protected]" },  { key: "sara", name: "Sara Johnson", role: "CMO", status: "On Leave", email: "[email protected]" },  {    key: "michael",    name: "Michael Brown",    role: "CFO",    status: "Active",    email: "[email protected]",  },] as const;const styles = stylex.create({ content: { minWidth: 600 } });
export function Basic() {  return (    <Table>      <Table.ScrollContainer>        <Table.Content aria-label="Team members" xstyle={styles.content}>          <Table.Header>            <Table.Column columnKey="name">Name</Table.Column>            <Table.Column columnKey="role">Role</Table.Column>            <Table.Column columnKey="status">Status</Table.Column>            <Table.Column columnKey="email">Email</Table.Column>          </Table.Header>          <Table.Body>            <Table.Collection items={rows}>              {(row) => (                <Table.Row itemKey={row.key}>                  <Table.Cell>{row.name}</Table.Cell>                  <Table.Cell>{row.role}</Table.Cell>                  <Table.Cell>{row.status}</Table.Cell>                  <Table.Cell>{row.email}</Table.Cell>                </Table.Row>              )}            </Table.Collection>          </Table.Body>        </Table.Content>      </Table.ScrollContainer>    </Table>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

组件结构

import { Table } from '@lenso/ui';
export default () => (  <Table>    <Table.ScrollContainer>      <Table.Content aria-label="Example table">        <Table.Header>          <Table.Column allowsSorting>            {({ sortDirection }) => (              <Table.SortableColumnHeader sortDirection={sortDirection}>                Name              </Table.SortableColumnHeader>            )}          </Table.Column>          <Table.Column>Role</Table.Column>        </Table.Header>        <Table.Body>          <Table.Row>            <Table.Cell>Kate Moore</Table.Cell>            <Table.Cell>CEO</Table.Cell>          </Table.Row>        </Table.Body>      </Table.Content>    </Table.ScrollContainer>    <Table.Footer>{/* Optional footer content */}</Table.Footer>  </Table>);

示例

次要变体

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 secondary-variant adaptation (Apache-2.0).import { Table } from "@lenso/ui";import { Headers, Rows, styles, users } from "./data";export function SecondaryVariant() {  return (    <Table variant="secondary">      <Table.ScrollContainer>        <Table.Content aria-label="Team members" xstyle={styles.content}>          <Headers />          <Table.Body>            <Rows items={users.slice(0, 4)} />          </Table.Body>        </Table.Content>      </Table.ScrollContainer>    </Table>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

异步加载

使用 Table.LoadMore 实现无限滚动。它会渲染一个哨兵行,滚动到视口时触发 onLoadMore。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 async-loading adaptation (Apache-2.0).import { useCallback, useEffect, useRef, useState } from "react";import { Spinner, Table } from "@lenso/ui";import { Rows, styles, users } from "./data";export function AsyncLoading() {  const [count, setCount] = useState(6);  const [loading, setLoading] = useState(false);  const request = useRef<ReturnType<typeof setTimeout> | null>(null);  useEffect(    () => () => {      if (request.current) clearTimeout(request.current);    },    [],  );  const loadMore = useCallback(() => {    if (request.current || count >= users.length) return;    setLoading(true);    request.current = setTimeout(() => {      request.current = null;      setCount((previous) => previous + 6);      setLoading(false);    }, 1500);  }, [count]);  return (    <Table>      <Table.ScrollContainer xstyle={styles.viewport}>        <Table.Content aria-label="Async loading table" xstyle={styles.content}>          <Table.Header xstyle={styles.sticky}>            {["name", "role", "status", "email"].map((column) => (              <Table.Column key={column} columnKey={column}>                {column[0]!.toUpperCase() + column.slice(1)}              </Table.Column>            ))}          </Table.Header>          <Table.Body>            <Rows items={users.slice(0, count)} chips />            {count < users.length && (              <Table.LoadMore colSpan={4} loading={loading} hasMore onLoadMore={loadMore}>                <Table.LoadMoreContent>                  <Spinner size="md" />                </Table.LoadMoreContent>              </Table.LoadMore>            )}          </Table.Body>        </Table.Content>      </Table.ScrollContainer>    </Table>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

排序

在 Table.Column 上使用 allowsSorting 属性可启用列排序。在 Table.Content 上使用 sortDescriptor 与 onSortChange 管理排序状态。将标签包裹在 Table.SortableColumnHeader 中,并将列 render prop 的 sortDirection 转发以渲染默认升序/降序指示器。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 sorting adaptation (Apache-2.0).import { useState } from "react";import { Table, type SortDescriptor } from "@lenso/ui";import { Headers, Rows, styles, users, type User } from "./data";export function Sorting() {  const [sort, setSort] = useState<SortDescriptor>({ column: "name", direction: "ascending" });  const sorted = users    .slice(0, 5)    .sort(      (a, b) =>        String(a[sort.column as keyof User]).localeCompare(String(b[sort.column as keyof User])) *        (sort.direction === "ascending" ? 1 : -1),    );  return (    <Table>      <Table.ScrollContainer>        <Table.Content          aria-label="Sortable table"          xstyle={styles.content}          sortDescriptor={sort}          onSortChange={setSort}        >          <Headers sorting />          <Table.Body>            <Rows items={sorted} />          </Table.Body>        </Table.Content>      </Table.ScrollContainer>    </Table>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

选择

在 Table.Content 上使用 selectionMode 启用行选择。使用 slot="selection" 的 Checkbox 实现全选与逐行勾选。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 selection adaptation (Apache-2.0).import { useState, type Key } from "react";import * as stylex from "@stylexjs/stylex";import { Table } from "@lenso/ui";import { Headers, Rows, styles, users } from "./data";export function SelectionDemo() {  const [selected, setSelected] = useState<Set<Key>>(new Set());  return (    <div {...stylex.props(styles.stack)}>      <Table>        <Table.ScrollContainer>          <Table.Content            aria-label="Table with selection"            xstyle={styles.content}            selectionMode="multiple"            selectedKeys={selected}            onSelectionChange={setSelected}          >            <Headers selection />            <Table.Body>              <Rows items={users.slice(0, 4)} selection />            </Table.Body>          </Table.Content>        </Table.ScrollContainer>      </Table>      <p {...stylex.props(styles.muted)}>        Selected: {selected.size ? [...selected].join(", ") : "None"}      </p>    </div>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

可展开行

行可嵌套以展示层级数据。使用 treeColumn 指定列,并在该列单元格中渲染 slot="chevron" 的 Button,供用户展开/收起行。使用 expandedKeys 控制哪些行处于展开状态。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 expandable-rows adaptation (Apache-2.0).import { useState, type Key } from "react";import * as stylex from "@stylexjs/stylex";import { Icon } from "@iconify/react";import { Table } from "@lenso/ui";type Row = { key: string; title: string; type: string; date: string; children: Row[] };const file = (key: string, title: string, date: string, children: Row[] = []): Row => ({  key,  title,  date,  children,  type: children.length ? "Directory" : "File",});const rows = [  file("1", "Documents", "10/20/2025", [    file("2", "Project", "8/2/2025", [      file("3", "Weekly Report", "7/10/2025"),      file("4", "Budget", "8/20/2025"),    ]),  ]),  file("5", "Photos", "2/3/2026", [    file("6", "Image 1", "1/23/2026"),    file("7", "Image 2", "2/3/2026"),  ]),];const styles = stylex.create({  content: { minWidth: 520 },  title: { display: "flex", alignItems: "center", gap: 4 },  chevron: { transform: "rotate(90deg)" },  collapsed: { transform: { default: "none", ":dir(rtl)": "rotate(180deg)" } },});export function ExpandableRows() {  const [expanded, setExpanded] = useState<Set<Key>>(new Set(["1"]));  const renderRow = (item: Row): React.ReactNode => (    <Table.Row itemKey={item.key} textValue={item.title}>      <Table.Cell columnKey="name">        {({ hasChildItems, isExpanded, isTreeColumn }) => (          <span {...stylex.props(styles.title)}>            {hasChildItems && isTreeColumn && (              <Table.ExpandButton aria-label={`Toggle ${item.title}`}>                <Icon                  icon="gravity-ui:chevron-right"                  width={16}                  aria-hidden="true"                  {...stylex.props(isExpanded ? styles.chevron : styles.collapsed)}                />              </Table.ExpandButton>            )}            <span>{item.title}</span>          </span>        )}      </Table.Cell>      <Table.Cell>{item.type}</Table.Cell>      <Table.Cell>{item.date}</Table.Cell>      <Table.Collection items={item.children}>{renderRow}</Table.Collection>    </Table.Row>  );  return (    <Table>      <Table.ScrollContainer>        <Table.Content          aria-label="Files"          xstyle={styles.content}          treeColumn="name"          expandedKeys={expanded}          onExpandedChange={setExpanded}        >          <Table.Header>            <Table.Column columnKey="name">Name</Table.Column>            <Table.Column columnKey="type">Type</Table.Column>            <Table.Column columnKey="date">Date Modified</Table.Column>          </Table.Header>          <Table.Body items={rows}>{renderRow}</Table.Body>        </Table.Content>      </Table.ScrollContainer>    </Table>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

分页

使用 Table.Footer 在表格下方添加分页组件。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 pagination adaptation (Apache-2.0).import { useState } from "react";import { Table } from "@lenso/ui";import { Headers, Pages, Rows, styles, users } from "./data";export function PaginationDemo() {  const [page, setPage] = useState(1);  return (    <Table>      <Table.ScrollContainer>        <Table.Content aria-label="Table with pagination" xstyle={styles.content}>          <Headers />          <Table.Body>            <Rows items={users.slice((page - 1) * 4, page * 4)} />          </Table.Body>        </Table.Content>      </Table.ScrollContainer>      <Table.Footer>        <Pages page={page} count={2} total={8} setPage={setPage} />      </Table.Footer>    </Table>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

列宽调整

将表格包裹在 Table.ResizableContainer 中,并在每个可调整宽度的列内添加 Table.ColumnResizer。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 column-resizing adaptation (Apache-2.0).import { Table } from "@lenso/ui";import { Headers, Rows, styles, users } from "./data";export function ColumnResizing() {  return (    <Table>      <Table.ResizableContainer>        <Table.Content aria-label="Table with resizable columns" xstyle={styles.resizing}>          <Headers resizing />          <Table.Body>            <Rows items={users.slice(0, 5)} chips />          </Table.Body>        </Table.Content>      </Table.ResizableContainer>    </Table>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

空状态

在 Table.Body 上使用 renderEmptyState,在表格无数据时展示自定义消息。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 empty-state adaptation (Apache-2.0).import * as stylex from "@stylexjs/stylex";import { Icon } from "@iconify/react";import { EmptyState, Table } from "@lenso/ui";import { Headers, styles } from "./data";const empty = stylex.create({  root: { minHeight: 200 },  content: {    minHeight: 140,    display: "flex",    flexDirection: "column",    alignItems: "center",    justifyContent: "center",    gap: 16,    textAlign: "center",    color: "var(--muted)",  },});export function EmptyStateDemo() {  return (    <Table xstyle={empty.root}>      <Table.ScrollContainer>        <Table.Content aria-label="Empty table" xstyle={styles.content}>          <Headers />          <Table.Body>            <tr>              <td colSpan={4}>                <EmptyState xstyle={empty.content}>                  <Icon icon="gravity-ui:tray" width={24} aria-hidden="true" />                  <span>No results found</span>                </EmptyState>              </td>            </tr>          </Table.Body>        </Table.Content>      </Table.ScrollContainer>    </Table>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

虚拟滚动

Table 通过 Virtualizer 支持虚拟化,仅渲染视口内可见行,从而高效展示大数据集。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 virtualization adaptation (Apache-2.0); native row spacers.import { Table } from "@lenso/ui";import { styles } from "./data";const first = [  "Emma",  "Liam",  "Olivia",  "Noah",  "Ava",  "James",  "Sophia",  "Oliver",  "Isabella",  "Lucas",  "Mia",  "Ethan",  "Charlotte",  "Mason",  "Amelia",  "Logan",  "Harper",  "Alexander",  "Ella",  "Benjamin",];const last = [  "Smith",  "Johnson",  "Williams",  "Brown",  "Jones",  "Garcia",  "Miller",  "Davis",  "Rodriguez",  "Martinez",  "Anderson",  "Taylor",  "Thomas",  "Jackson",  "White",  "Harris",  "Clark",  "Lewis",  "Robinson",  "Walker",];const roles = [  "Software Engineer",  "Senior Engineer",  "Staff Engineer",  "Product Manager",  "Designer",  "Data Analyst",  "QA Engineer",  "DevOps Engineer",  "Marketing Manager",  "Sales Representative",];const users = Array.from({ length: 1000 }, (_, index) => ({  key: index + 1,  name: `${first[index % 20]} ${last[Math.floor(index / 20) % 20]}`,  role: roles[index % 10],  email: `${first[index % 20]!.toLowerCase()}.${last[Math.floor(index / 20) % 20]!.toLowerCase()}@acme.com`,}));export function Virtualization() {  return (    <Table>      <Table.ScrollContainer xstyle={styles.virtualViewport}>        <Table.Content aria-label="Virtualized table with 1000 rows" xstyle={styles.resizing}>          <Table.Header xstyle={styles.sticky}>            <Table.Column columnKey="name" minWidth={160}>              Name            </Table.Column>            <Table.Column columnKey="role" minWidth={220}>              Role            </Table.Column>            <Table.Column columnKey="email" minWidth={240}>              Email            </Table.Column>          </Table.Header>          <Table.Body items={users} virtualized={{ height: 300, rowHeight: 42 }}>            {(user) => (              <Table.Row itemKey={user.key}>                <Table.Cell>{user.name}</Table.Cell>                <Table.Cell>{user.role}</Table.Cell>                <Table.Cell>{user.email}</Table.Cell>              </Table.Row>            )}          </Table.Body>        </Table.Content>      </Table.ScrollContainer>    </Table>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

TanStack Table

HeroUI 的 Table 作为无头表格库之上的渲染层。 本示例使用 TanStack Table 处理列定义、排序与分页,而 HeroUI 负责样式与无障碍。

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 tanstack-table adaptation (Apache-2.0); retains the v9 data model.import { useState } from "react";import { Table, type SortDescriptor } from "@lenso/ui";import {  createColumnHelper,  createPaginatedRowModel,  createSortedRowModel,  flexRender,  rowPaginationFeature,  rowSortingFeature,  sortFn_alphanumeric,  tableFeatures,  useTable,  type SortingState,} from "@tanstack/react-table";import { Pages, Status, styles, users, type User } from "./data";const features = tableFeatures({  paginatedRowModel: createPaginatedRowModel(),  rowPaginationFeature,  rowSortingFeature,  sortFns: { alphanumeric: sortFn_alphanumeric },  sortedRowModel: createSortedRowModel(),});const helper = createColumnHelper<typeof features, User>();const columns = helper.columns([  helper.accessor("name", { header: "Name" }),  helper.accessor("role", { header: "Role" }),  helper.accessor("status", {    header: "Status",    cell: (info) => <Status status={info.getValue()} />,  }),  helper.accessor("email", { header: "Email" }),]);const data = users.slice(0, 8);export function TanstackTable() {  const [sorting, setSorting] = useState<SortingState>([]);  const table = useTable({    columns,    data,    features,    initialState: { pagination: { pageIndex: 0, pageSize: 4 } },    onSortingChange: setSorting,    state: { sorting },  });  const first = sorting[0];  const descriptor: SortDescriptor | undefined = first    ? { column: first.id, direction: first.desc ? "descending" : "ascending" }    : undefined;  return (    <Table>      <Table.ScrollContainer>        <Table.Content          aria-label="TanStack Table example"          xstyle={styles.content}          sortDescriptor={descriptor}          onSortChange={(next) =>            setSorting([{ id: String(next.column), desc: next.direction === "descending" }])          }        >          <Table.Header>            {table.getHeaderGroups()[0]?.headers.map((header) => (              <Table.Column                key={header.id}                columnKey={header.id}                allowsSorting={header.column.getCanSort()}              >                {({ sortDirection }) => (                  <Table.SortableColumnHeader sortDirection={sortDirection}>                    {flexRender(header.column.columnDef.header, header.getContext())}                  </Table.SortableColumnHeader>                )}              </Table.Column>            ))}          </Table.Header>          <Table.Body>            {table.getRowModel().rows.map((row) => (              <Table.Row key={row.id} itemKey={row.id}>                {row.getAllCells().map((cell) => (                  <Table.Cell key={cell.id}>                    {flexRender(cell.column.columnDef.cell, cell.getContext())}                  </Table.Cell>                ))}              </Table.Row>            ))}          </Table.Body>        </Table.Content>      </Table.ScrollContainer>      <Table.Footer>        <Pages          page={table.state.pagination.pageIndex + 1}          count={table.getPageCount()}          total={8}          setPage={(page) => table.setPageIndex(page - 1)}        />      </Table.Footer>    </Table>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

自定义单元格

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 custom-cells adaptation (Apache-2.0).import { useState, type Key } from "react";import * as stylex from "@stylexjs/stylex";import { Icon } from "@iconify/react";import { Avatar, Button, Table, type SortDescriptor } from "@lenso/ui";import { Status, styles, users, type User } from "./data";const workers = users.slice(0, 5).map((user, index) => ({  ...user,  key: [4586932, 5273849, 7492836, 8293746, 1234567][index]!,  role: [    "Chief Executive Officer",    "Chief Technology Officer",    "Chief Marketing Officer",    "Chief Financial Officer",    "Product Manager",  ][index]!,  color: ["red", "green", "blue", "purple", "orange"][index],}));export function CustomCells() {  const [selected, setSelected] = useState<Set<Key>>(new Set());  const [sort, setSort] = useState<SortDescriptor>({ column: "name", direction: "ascending" });  const sorted = [...workers].sort(    (a, b) =>      String(a[sort.column as keyof User]).localeCompare(String(b[sort.column as keyof User])) *      (sort.direction === "ascending" ? 1 : -1),  );  return (    <Table>      <Table.ScrollContainer>        <Table.Content          aria-label="Table with custom cells"          xstyle={styles.customCells}          selectionMode="multiple"          selectedKeys={selected}          onSelectionChange={setSelected}          sortDescriptor={sort}          onSortChange={setSort}        >          <Table.Header>            <Table.Column columnKey="selection" width={48}>              <Table.SelectionCheckbox />            </Table.Column>            {[              ["key", "Worker ID"],              ["name", "Member"],              ["role", "Role"],              ["status", "Status"],            ].map(([key, title]) => (              <Table.Column key={key} columnKey={key!} allowsSorting>                {({ sortDirection }) => (                  <Table.SortableColumnHeader sortDirection={sortDirection}>                    {title}                  </Table.SortableColumnHeader>                )}              </Table.Column>            ))}            <Table.Column columnKey="actions">Actions</Table.Column>          </Table.Header>          <Table.Body>            {sorted.map((user) => (              <Table.Row key={user.key} itemKey={user.key}>                <Table.Cell>                  <Table.SelectionCheckbox aria-label={`Select ${user.name}`} />                </Table.Cell>                <Table.Cell>                  <div {...stylex.props(styles.row)}>                    #{user.key}                    <Button                      isIconOnly                      aria-label={`Copy ID #${user.key}`}                      size="sm"                      variant="ghost"                    >                      <Icon icon="gravity-ui:copy" width={16} aria-hidden="true" />                    </Button>                  </div>                </Table.Cell>                <Table.Cell>                  <div {...stylex.props(styles.row)}>                    <Avatar size="sm">                      <Avatar.Image                        alt={user.name}                        src={`https://heroui-assets.nyc3.cdn.digitaloceanspaces.com/avatars/${user.color}.jpg`}                      />                      <Avatar.Fallback>                        {user.name                          .split(" ")                          .map((name) => name[0])                          .join("")}                      </Avatar.Fallback>                    </Avatar>                    <div {...stylex.props(styles.detail)}>                      <span>{user.name}</span>                      <span {...stylex.props(styles.muted)}>{user.email}</span>                    </div>                  </div>                </Table.Cell>                <Table.Cell>{user.role}</Table.Cell>                <Table.Cell>                  <Status status={user.status} />                </Table.Cell>                <Table.Cell>                  <div {...stylex.props(styles.row)}>                    {(["View", "Edit", "Delete"] as const).map((action, index) => (                      <Button                        key={action}                        isIconOnly                        aria-label={`${action} ${user.name}`}                        size="sm"                        variant={action === "Delete" ? "danger-soft" : "tertiary"}                      >                        <Icon                          icon={`gravity-ui:${["eye", "pencil", "trash-bin"][index]}`}                          width={16}                          aria-hidden="true"                        />                      </Button>                    ))}                  </div>                </Table.Cell>              </Table.Row>            ))}          </Table.Body>        </Table.Content>      </Table.ScrollContainer>    </Table>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

自定义样式

Tailwind CSS

此预览复用英文版适配,不代表中文源示例已完成本地实现。

"use client";// HeroUI v3.2.6 custom-styles adaptation (Apache-2.0).import { Table } from "@lenso/ui";import { Headers, Rows, styles, users } from "./data";export function CustomStyles() {  return (    <Table xstyle={styles.customRoot}>      <Table.ScrollContainer>        <Table.Content aria-label="Team members" xstyle={styles.content}>          <Headers custom email={false} />          <Table.Body>            <Rows items={users.slice(0, 3)} custom email={false} />          </Table.Body>        </Table.Content>      </Table.ScrollContainer>    </Table>  );}

Local adaptation source above. Derived from HeroUI v3.2.6 source.

全局 CSS

若要自定义组件类,可使用 @layer components 指令。了解更多。

@layer components {  .table-root {    @apply relative grid w-full overflow-clip;  }
  .table__header {    @apply bg-gray-100;  }
  .table__column {    @apply px-4 py-2.5 text-left text-xs font-medium text-gray-600;  }
  .table__row {    @apply bg-white border-b border-gray-200;  }
  .table__cell {    @apply px-4 py-3 text-sm;  }
  .table__footer {    @apply flex items-center px-4 py-2.5;  }}

样式参考

HeroUI 遵循 BEM 方法论,确保组件变体与状态可复用且易于自定义。

CSS 类

Table 组件使用以下 CSS 类(查看源码样式):

基础类 [!toc]

  • .table-root - 根容器(命名为 table-root 而非 table,因为 table 是 Tailwind CSS 内置的 display: table 工具类)
  • .table__scroll-container - 横向滚动包裹层与自定义滚动条
  • .table__content - <table> 元素
  • .table__header - 表头行(<thead>)
  • .table__column - 列表头单元格(<th>)
  • .table__body - 表体(<tbody>)
  • .table__row - 行(<tr>)
  • .table__cell - 数据单元格(<td>)
  • .table__footer - 表底容器(位于 table 外部)

进阶类 [!toc]

  • .table__column-resizer - 列宽拖拽手柄
  • .table__resizable-container - 启用列宽调整的包裹层
  • .table__load-more - 无限滚动的哨兵行
  • .table__load-more-content - 加载指示器的样式容器
  • .table__sortable-column-header - 可排序列标签与指示器的包裹层
  • .table__sortable-column-indicator - 排序方向 chevron(通过 [data-direction="descending"] 翻转)

变体类 [!toc]

  • .table-root--primary - 灰色背景容器与卡片式表体(默认)
  • .table-root--secondary - 无背景,独立圆角表头

交互状态

Table 同时支持 CSS 伪类与 data 属性,以提供更灵活的状态控制:

  • 悬停::hover 或 [data-hovered="true"](行背景变化)
  • 已选中:[data-selected="true"](行高亮)
  • 聚焦::focus-visible 或 [data-focus-visible="true"](行、列与单元格的内嵌焦点环)
  • 禁用::disabled 或 [aria-disabled="true"](降低透明度)
  • 可排序:[data-allows-sorting="true"](列上的交互指针样式)
  • 拖动中:[data-dragging="true"](降低透明度)
  • 放置目标:[data-drop-target="true"](强调色背景)

API 参考

Table

Prop类型默认值描述
variant"primary" | "secondary""primary"视觉变体。Primary 为灰色背景容器;Secondary 为扁平透明行。
classNamestring-根容器的额外 CSS 类。
childrenReact.ReactNode-表格内容(ScrollContainer、Footer 等)。

Table.ScrollContainer

Prop类型默认值描述
classNamestring-额外的 CSS 类。
childrenReact.ReactNode-Table.Content 元素。

Table.Content

继承自 React Aria Table。

Prop类型默认值描述
aria-labelstring-表格的无障碍标签。
selectionMode"none" | "single" | "multiple""none"选择行为。
selectedKeysSelection-受控的已选中 key。
onSelectionChange(keys: Selection) => void-选择变化时的事件处理函数。
sortDescriptorSortDescriptor-当前排序状态。
onSortChange(descriptor: SortDescriptor) => void-排序变化时的事件处理函数。
classNamestring-额外的 CSS 类。

Table.Header

继承自 React Aria TableHeader。

Prop类型默认值描述
columnsT[]-渲染函数模式下的动态列数据。
childrenReact.ReactNode | (column: T) => React.ReactNode-静态列或渲染函数。

Table.Column

继承自 React Aria Column。

Prop类型默认值描述
idstring-列标识符。
allowsSortingbooleanfalse列是否可排序。
isRowHeaderbooleanfalse该列是否作为行表头。
defaultWidthstring | number-可调整列的默认宽度。
minWidthnumber-可调整列的最小宽度。
childrenReact.ReactNode | (values: ColumnRenderProps) => React.ReactNode-列内容或带排序方向的渲染函数。

Table.Body

继承自 React Aria TableBody。

Prop类型默认值描述
itemsT[]-渲染函数模式下的动态行数据。
renderEmptyState() => React.ReactNode-表格为空时展示的内容。
childrenReact.ReactNode | (item: T) => React.ReactNode-静态行或渲染函数。

Table.Row

继承自 React Aria Row。

Prop类型默认值描述
idstring | number-行标识符。
classNamestring-额外的 CSS 类。
childrenReact.ReactNode-行单元格。

Table.Cell

继承自 React Aria Cell。

Prop类型默认值描述
classNamestring-额外的 CSS 类。
childrenReact.ReactNode-单元格内容。

Table.SortableColumnHeader

渲染可排序列的标签与升序 / 降序指示器。请在 Table.Column 的渲染函数回调中使用,并将 sortDirection 透传进来。

Prop类型默认值描述
sortDirection"ascending" | "descending"-当前排序方向。请从 Table.Column 的渲染函数中透传。
showIndicatorbooleantrue当存在排序方向时是否渲染指示器图标。
indicatorReact.ReactNode-自定义指示器元素。会覆盖默认的 chevron,并会被自动注入 data-direction 属性。
classNamestring-包裹元素的额外 CSS 类。
childrenReact.ReactNode-列标签内容。

Table.Footer

Prop类型默认值描述
classNamestring-额外的 CSS 类。
childrenReact.ReactNode-表底内容(例如分页)。

Table.ColumnResizer

继承自 React Aria ColumnResizer。

Prop类型默认值描述
classNamestring-额外的 CSS 类。

Table.ResizableContainer

继承自 React Aria ResizableTableContainer。

Prop类型默认值描述
classNamestring-额外的 CSS 类。
childrenReact.ReactNode-Table.Content 元素。

Table.LoadMore

继承自 React Aria TableLoadMoreItem。

Prop类型默认值描述
isLoadingbooleanfalse数据是否正在加载。
onLoadMore() => void-哨兵行可见时的事件处理函数。
childrenReact.ReactNode-加载指示器内容。

Table.LoadMoreContent

Prop类型默认值描述
classNamestring-额外的 CSS 类。
childrenReact.ReactNode-加载指示器内容(例如 Spinner)。

Table.Collection

由 React Aria Collection 重新导出。用于在行内与静态单元格并存时渲染动态单元格(例如复选框)。

Prop类型默认值描述
itemsT[]-集合条目。
children(item: T) => React.ReactNode-每个条目的渲染函数。

TableLayout

Name类型默认值描述
rowHeightnumber | undefined48行的固定高度(px)。
estimatedRowHeightnumber | undefined—行高可变时的估算高度。
headingHeightnumber | undefined48分区表头的固定高度(px)。
estimatedHeadingHeightnumber | undefined—表头高度可变时的估算高度。
loaderHeightnumber | undefined48加载器元素的固定高度(px)。该加载器用于在根级或嵌套行/分区中渲染「加载更多」等加载行。
dropIndicatorThicknessnumber | undefined2放置指示器的线条粗细。
gapnumber | undefined0条目之间的间距。
paddingnumber | undefined0列表的内边距。

相关组件