Table 表格
@lark-ui/core
主题发件人日期
Lark v1.0.0 已发布Visal In5 秒前
新的工作机会Lark10 分钟前
每日邮件摘要Lark1 小时前
import { LayerCard, Table } from "@lark-ui/core";

export function TableBasicDemo() {
  return (
    <LayerCard className="p-0">
      <Table>
        <Table.Header>
          <Table.Row>
            <Table.Head>主题</Table.Head>
            <Table.Head>发件人</Table.Head>
            <Table.Head>日期</Table.Head>
          </Table.Row>
        </Table.Header>
        <Table.Body>
          {emailData.slice(0, 3).map((row) => (
            <Table.Row key={row.id}>
              <Table.Cell>{row.subject}</Table.Cell>
              <Table.Cell>{row.from}</Table.Cell>
              <Table.Cell>{row.date}</Table.Cell>
            </Table.Row>
          ))}
        </Table.Body>
      </Table>
    </LayerCard>
  );
}

安装

统一导出

import { Table } from "@lark-ui/core";

按需导出

import { Table } from "@lark-ui/core/components/table";

用法

import { Table, LayerCard } from "@lark-ui/core";

export default function Example() {
  return (
    <LayerCard className="p-0">
      <Table>
        <Table.Header>
          <Table.Row>
            <Table.Head>Name</Table.Head>
            <Table.Head>Email</Table.Head>
            <Table.Head>Role</Table.Head>
          </Table.Row>
        </Table.Header>
        <Table.Body>
          <Table.Row>
            <Table.Cell>John Doe</Table.Cell>
            <Table.Cell>john@example.com</Table.Cell>
            <Table.Cell>Admin</Table.Cell>
          </Table.Row>
        </Table.Body>
      </Table>
    </LayerCard>
  );
}

示例

带复选框

使用 Table.CheckHead 和 Table.CheckCell 添加行选择。两者都接受 onCheckedChange,其签名与底层 Checkbox(复选框)组件一致,并通过第二个参数提供可选的事件详情。

较早的 onValueChange 属性仍然可用,但已被弃用——lint 规则会对其标记警告,并将在未来的主版本中移除。请通过重命名该属性完成迁移:

// Before (deprecated)
<Table.CheckCell onValueChange={(checked) => toggleRow(id)} />

// After
<Table.CheckCell onCheckedChange={(checked) => toggleRow(id)} />

// With event details
<Table.CheckCell
  onCheckedChange={(checked, eventDetails) => {
    toggleRow(id);
    eventDetails?.event.stopPropagation();
  }}
/>
主题发件人日期
Lark v1.0.0 已发布Visal In5 秒前
新的工作机会Lark10 分钟前
每日邮件摘要Lark1 小时前
import { useState } from "react";
import { LayerCard, Table } from "@lark-ui/core";

export function TableWithCheckboxDemo() {
  const rows = emailData.slice(0, 3);
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());

  const toggleRow = (id: string) => {
    setSelectedIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) {
        next.delete(id);
      } else {
        next.add(id);
      }
      return next;
    });
  };

  const toggleAll = () => {
    if (selectedIds.size === rows.length) {
      setSelectedIds(new Set());
    } else {
      setSelectedIds(new Set(rows.map((r) => r.id)));
    }
  };

  return (
    <LayerCard className="p-0">
      <Table>
        <Table.Header>
          <Table.Row>
            <Table.CheckHead
              checked={selectedIds.size === rows.length}
              indeterminate={
                selectedIds.size > 0 && selectedIds.size < rows.length
              }
              onCheckedChange={toggleAll}
              aria-label="选择所有行"
            />
            <Table.Head>主题</Table.Head>
            <Table.Head>发件人</Table.Head>
            <Table.Head>日期</Table.Head>
          </Table.Row>
        </Table.Header>
        <Table.Body>
          {rows.map((row) => (
            <Table.Row key={row.id}>
              <Table.CheckCell
                checked={selectedIds.has(row.id)}
                onCheckedChange={() => toggleRow(row.id)}
                aria-label={`选择 ${row.subject}`}
              />
              <Table.Cell>{row.subject}</Table.Cell>
              <Table.Cell>{row.from}</Table.Cell>
              <Table.Cell>{row.date}</Table.Cell>
            </Table.Row>
          ))}
        </Table.Body>
      </Table>
    </LayerCard>
  );
}

紧凑表头

在 Table.Header 上使用 variant="compact" 可获得更紧凑的表头样式。

主题发件人日期
Lark v1.0.0 已发布Visal In5 秒前
新的工作机会Lark10 分钟前
每日邮件摘要Lark1 小时前
import { LayerCard, Table } from "@lark-ui/core";

export function TableWithCompactHeaderDemo() {
  return (
    <LayerCard className="p-0">
      <Table>
        <Table.Header variant="compact">
          <Table.Row>
            <Table.Head>主题</Table.Head>
            <Table.Head>发件人</Table.Head>
            <Table.Head>日期</Table.Head>
          </Table.Row>
        </Table.Header>
        <Table.Body>
          {emailData.slice(0, 3).map((row) => (
            <Table.Row key={row.id}>
              <Table.Cell>{row.subject}</Table.Cell>
              <Table.Cell>{row.from}</Table.Cell>
              <Table.Cell>{row.date}</Table.Cell>
            </Table.Row>
          ))}
        </Table.Body>
      </Table>
    </LayerCard>
  );
}

选中行

在 Table.Row 上使用 variant="selected" 可高亮选中的行。

主题发件人日期
Lark v1.0.0 已发布Visal In5 秒前
新的工作机会Lark10 分钟前
每日邮件摘要Lark1 小时前
import { useState } from "react";
import { LayerCard, Table } from "@lark-ui/core";

export function TableSelectedRowDemo() {
  const rows = emailData.slice(0, 3);
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set(["2"]));

  const toggleRow = (id: string) => {
    setSelectedIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) {
        next.delete(id);
      } else {
        next.add(id);
      }
      return next;
    });
  };

  const toggleAll = () => {
    if (selectedIds.size === rows.length) {
      setSelectedIds(new Set());
    } else {
      setSelectedIds(new Set(rows.map((r) => r.id)));
    }
  };

  return (
    <LayerCard className="p-0">
      <Table>
        <Table.Header>
          <Table.Row>
            <Table.CheckHead
              checked={selectedIds.size === rows.length}
              indeterminate={
                selectedIds.size > 0 && selectedIds.size < rows.length
              }
              onCheckedChange={toggleAll}
              aria-label="选择所有行"
            />
            <Table.Head>主题</Table.Head>
            <Table.Head>发件人</Table.Head>
            <Table.Head>日期</Table.Head>
          </Table.Row>
        </Table.Header>
        <Table.Body>
          {rows.map((row) => (
            <Table.Row
              key={row.id}
              variant={selectedIds.has(row.id) ? "selected" : "default"}
            >
              <Table.CheckCell
                checked={selectedIds.has(row.id)}
                onCheckedChange={() => toggleRow(row.id)}
                aria-label={`选择 ${row.subject}`}
              />
              <Table.Cell>{row.subject}</Table.Cell>
              <Table.Cell>{row.from}</Table.Cell>
              <Table.Cell>{row.date}</Table.Cell>
            </Table.Row>
          ))}
        </Table.Body>
      </Table>
    </LayerCard>
  );
}

固定布局与列宽

如需精确控制列宽,请设置 layout="fixed" 并搭配 col 元素使用 colgroup。

主题发件人日期
Lark v1.0.0 已发布Visal In5 秒前
新的工作机会Lark10 分钟前
每日邮件摘要Lark1 小时前
GitLab - 新评论Rob Knecht1 天前
不在办公室Johnnie Lappen3 天前
import { LayerCard, Table } from "@lark-ui/core";

export function TableFixedLayoutDemo() {
  return (
    <LayerCard className="p-0">
      <Table layout="fixed">
        <colgroup>
          <col />
          <col className="w-[150px]" />
          <col className="w-[150px]" />
        </colgroup>
        <Table.Header>
          <Table.Row>
            <Table.Head>主题</Table.Head>
            <Table.Head>发件人</Table.Head>
            <Table.Head>日期</Table.Head>
          </Table.Row>
        </Table.Header>
        <Table.Body>
          {emailData.map((row) => (
            <Table.Row key={row.id}>
              <Table.Cell>{row.subject}</Table.Cell>
              <Table.Cell>{row.from}</Table.Cell>
              <Table.Cell>{row.date}</Table.Cell>
            </Table.Row>
          ))}
        </Table.Body>
      </Table>
    </LayerCard>
  );
}

粘性列

在 Table.Head 和 Table.Cell 上设置 sticky="left" 或 sticky="right", 即可将列固定在滚动容器的左侧或右侧边缘。组件会自动添加不透明背景和渐变淡出效果。 请用 overflow-x-auto 容器包裹表格。

主题发件人日期标签操作
Lark v1.0.0 已发布Visal In5 秒前—
新的工作机会Lark10 分钟前—
每日邮件摘要Lark1 小时前
促销
GitLab - 新评论Rob Knecht1 天前—
不在办公室Johnnie Lappen3 天前—
import { Badge, Button, DropdownMenu, LayerCard, Table } from "@lark-ui/core";
import { DotsThree, Eye, PencilSimple, Trash } from "@phosphor-icons/react";

/**
 * 演示固定在右侧的操作列,表格横向滚动时该列保持不动。
 * 在 `Table.Head` 和 `Table.Cell` 上使用 `sticky="right"`——渐变淡出和不透明背景
 * 会自动应用。
 */
export function TableStickyColumnDemo() {
  return (
    <LayerCard className="w-full max-w-md overflow-x-auto p-0">
      <Table>
        <Table.Header>
          <Table.Row>
            <Table.Head>主题</Table.Head>
            <Table.Head>发件人</Table.Head>
            <Table.Head>日期</Table.Head>
            <Table.Head>标签</Table.Head>
            <Table.Head sticky="right">
              <span className="sr-only">操作</span>
            </Table.Head>
          </Table.Row>
        </Table.Header>
        <Table.Body>
          {emailData.map((row) => (
            <Table.Row key={row.id}>
              <Table.Cell className="whitespace-nowrap">
                {row.subject}
              </Table.Cell>
              <Table.Cell className="whitespace-nowrap">{row.from}</Table.Cell>
              <Table.Cell className="whitespace-nowrap">{row.date}</Table.Cell>
              <Table.Cell className="whitespace-nowrap">
                {row.tags ? (
                  <div className="inline-flex gap-1">
                    {row.tags.map((tag) => (
                      <Badge key={tag}>{tag}</Badge>
                    ))}
                  </div>
                ) : (
                  "—"
                )}
              </Table.Cell>
              <Table.Cell sticky="right" className="text-right">
                <DropdownMenu>
                  <DropdownMenu.Trigger
                    render={
                      <Button
                        variant="ghost"
                        size="sm"
                        shape="square"
                        aria-label="更多选项"
                      >
                        <DotsThree weight="bold" size={16} />
                      </Button>
                    }
                  />
                  <DropdownMenu.Content>
                    <DropdownMenu.Item icon={Eye}>查看</DropdownMenu.Item>
                    <DropdownMenu.Item icon={PencilSimple}>
                      编辑
                    </DropdownMenu.Item>
                    <DropdownMenu.Separator />
                    <DropdownMenu.Item icon={Trash} variant="danger">
                      删除
                    </DropdownMenu.Item>
                  </DropdownMenu.Content>
                </DropdownMenu>
              </Table.Cell>
            </Table.Row>
          ))}
        </Table.Body>
      </Table>
    </LayerCard>
  );
}

紧凑表头与粘性列

将 Table.Header 上的 variant="compact" 与 sticky 列结合使用。

主题发件人日期标签操作
Lark v1.0.0 已发布Visal In5 秒前—
新的工作机会Lark10 分钟前—
每日邮件摘要Lark1 小时前
促销
GitLab - 新评论Rob Knecht1 天前—
不在办公室Johnnie Lappen3 天前—
import { Badge, Button, DropdownMenu, LayerCard, Table } from "@lark-ui/core";
import { DotsThree, Eye, PencilSimple, Trash } from "@phosphor-icons/react";

/**
 * 演示紧凑表头与粘性列的组合。该组合可能导致紧凑表头背景(`bg-lark-elevated`)
 * 与粘性单元格背景(`bg-lark-base`)之间出现视觉不一致。
 */
export function TableCompactStickyDemo() {
  return (
    <LayerCard className="w-full max-w-md overflow-x-auto p-0">
      <Table>
        <Table.Header variant="compact">
          <Table.Row>
            <Table.Head>主题</Table.Head>
            <Table.Head>发件人</Table.Head>
            <Table.Head>日期</Table.Head>
            <Table.Head>标签</Table.Head>
            <Table.Head sticky="right">
              <span className="sr-only">操作</span>
            </Table.Head>
          </Table.Row>
        </Table.Header>
        <Table.Body>
          {emailData.map((row) => (
            <Table.Row key={row.id}>
              <Table.Cell className="whitespace-nowrap">
                {row.subject}
              </Table.Cell>
              <Table.Cell className="whitespace-nowrap">{row.from}</Table.Cell>
              <Table.Cell className="whitespace-nowrap">{row.date}</Table.Cell>
              <Table.Cell className="whitespace-nowrap">
                {row.tags ? (
                  <div className="inline-flex gap-1">
                    {row.tags.map((tag) => (
                      <Badge key={tag}>{tag}</Badge>
                    ))}
                  </div>
                ) : (
                  "—"
                )}
              </Table.Cell>
              <Table.Cell sticky="right" className="text-right">
                <DropdownMenu>
                  <DropdownMenu.Trigger
                    render={
                      <Button
                        variant="ghost"
                        size="sm"
                        shape="square"
                        aria-label="更多选项"
                      >
                        <DotsThree weight="bold" size={16} />
                      </Button>
                    }
                  />
                  <DropdownMenu.Content>
                    <DropdownMenu.Item icon={Eye}>查看</DropdownMenu.Item>
                    <DropdownMenu.Item icon={PencilSimple}>
                      编辑
                    </DropdownMenu.Item>
                    <DropdownMenu.Separator />
                    <DropdownMenu.Item icon={Trash} variant="danger">
                      删除
                    </DropdownMenu.Item>
                  </DropdownMenu.Content>
                </DropdownMenu>
              </Table.Cell>
            </Table.Row>
          ))}
        </Table.Body>
      </Table>
    </LayerCard>
  );
}

完整示例

包含复选框、徽标(Badge)、操作按钮和固定列宽的完整表格。

主题发件人日期
Lark v1.0.0 已发布
Visal In5 秒前
新的工作机会
Lark10 分钟前
每日邮件摘要
促销
Lark1 小时前
GitLab - 新评论
Rob Knecht1 天前
不在办公室
Johnnie Lappen3 天前
import { useState } from "react";
import { Badge, Button, DropdownMenu, LayerCard, Table } from "@lark-ui/core";
import { DotsThree, EnvelopeSimple, Eye, PencilSimple, Trash } from "@phosphor-icons/react";

export function TableFullDemo() {
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set(["2"]));

  const toggleRow = (id: string) => {
    setSelectedIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) {
        next.delete(id);
      } else {
        next.add(id);
      }
      return next;
    });
  };

  const toggleAll = () => {
    if (selectedIds.size === emailData.length) {
      setSelectedIds(new Set());
    } else {
      setSelectedIds(new Set(emailData.map((r) => r.id)));
    }
  };

  return (
    <LayerCard className="w-full overflow-x-auto p-0">
      <Table layout="fixed">
        <colgroup>
          <col />{" "}
          {/* Checkbox column - width handled by Table.CheckHead/CheckCell */}
          <col />
          <col style={{ width: "150px" }} />
          <col style={{ width: "120px" }} />
          <col style={{ width: "50px" }} />
        </colgroup>
        <Table.Header>
          <Table.Row>
            <Table.CheckHead
              checked={selectedIds.size === emailData.length}
              indeterminate={
                selectedIds.size > 0 && selectedIds.size < emailData.length
              }
              onCheckedChange={toggleAll}
              aria-label="选择所有行"
            />
            <Table.Head>主题</Table.Head>
            <Table.Head>发件人</Table.Head>
            <Table.Head>日期</Table.Head>
            <Table.Head></Table.Head>
          </Table.Row>
        </Table.Header>
        <Table.Body>
          {emailData.map((row) => (
            <Table.Row
              key={row.id}
              variant={selectedIds.has(row.id) ? "selected" : "default"}
            >
              <Table.CheckCell
                checked={selectedIds.has(row.id)}
                onCheckedChange={() => toggleRow(row.id)}
                aria-label={`选择 ${row.subject}`}
              />
              <Table.Cell>
                <div className="flex items-center gap-2">
                  <EnvelopeSimple size={16} />
                  <span className="truncate">{row.subject}</span>
                  {row.tags && (
                    <div className="ml-2 inline-flex gap-1">
                      {row.tags.map((tag) => (
                        <Badge key={tag}>{tag}</Badge>
                      ))}
                    </div>
                  )}
                </div>
              </Table.Cell>
              <Table.Cell>
                <span className="truncate">{row.from}</span>
              </Table.Cell>
              <Table.Cell>
                <span className="truncate">{row.date}</span>
              </Table.Cell>
              <Table.Cell className="text-right">
                <DropdownMenu>
                  <DropdownMenu.Trigger
                    render={
                      <Button
                        variant="ghost"
                        size="sm"
                        shape="square"
                        aria-label="更多选项"
                      >
                        <DotsThree weight="bold" size={16} />
                      </Button>
                    }
                  />
                  <DropdownMenu.Content>
                    <DropdownMenu.Item icon={Eye}>查看</DropdownMenu.Item>
                    <DropdownMenu.Item icon={PencilSimple}>
                      编辑
                    </DropdownMenu.Item>
                    <DropdownMenu.Separator />
                    <DropdownMenu.Item icon={Trash} variant="danger">
                      删除
                    </DropdownMenu.Item>
                  </DropdownMenu.Content>
                </DropdownMenu>
              </Table.Cell>
            </Table.Row>
          ))}
        </Table.Body>
      </Table>
    </LayerCard>
  );
}

API 参考

Table

根表格组件。渲染语义化的 <table> 元素。

属性类型默认值说明
layout"auto" | "fixed""auto"-
variant"default" | "selected""default"-
sticky"left" | "right"--
classNamestring-额外的 CSS 类名
childrenReactNode-子元素

Table.Header

表头区域。渲染 <thead>。设置 sticky 可将表头行固定在滚动容器顶部。

Table.Body

表体区域。渲染 <tbody>。

Table.Row

表格行。支持 variant="selected" 以高亮显示。

属性类型默认值

该组件没有专有属性,支持标准 HTML 属性。

Table.Head

表头单元格。渲染 <th>。接受 sticky="left" 或 sticky="right" 来固定该列。

Table.Cell

表体单元格。渲染 <td>。接受 sticky="left" 或 sticky="right" 来固定该列。

Table.CheckHead

带复选框的表头单元格,用于「全选」功能。

属性类型默认值

该组件没有专有属性,支持标准 HTML 属性。

Table.CheckCell

带复选框的表体单元格,用于行选择。

属性类型默认值

该组件没有专有属性,支持标准 HTML 属性。

Table.ResizeHandle

用于调整列宽的可拖拽手柄。可配合 TanStack Table 或自定义的调整逻辑使用。

TanStack Table 集成

如需排序、筛选和可调整列宽等高级功能,请集成 TanStack Table。表格(Table)组件经过专门设计,可与 TanStack 的无头 API 无缝协作。

import {
  flexRender,
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table";
import { Table } from "@lark-ui/core";

function DataTable({ data, columns }) {
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    columnResizeMode: "onChange",
  });

  return (
    <Table layout="fixed">
      <colgroup>
        {table.getAllColumns().map((column) => (
          <col key={column.id} style={{ width: column.getSize() }} />
        ))}
      </colgroup>
      <Table.Header>
        {table.getHeaderGroups().map((headerGroup) => (
          <Table.Row key={headerGroup.id}>
            {headerGroup.headers.map((header) => (
              <Table.Head key={header.id}>
                {flexRender(
                  header.column.columnDef.header,
                  header.getContext(),
                )}
                <Table.ResizeHandle
                  onMouseDown={header.getResizeHandler()}
                  onTouchStart={header.getResizeHandler()}
                />
              </Table.Head>
            ))}
          </Table.Row>
        ))}
      </Table.Header>
      <Table.Body>
        {table.getRowModel().rows.map((row) => (
          <Table.Row key={row.id}>
            {row.getVisibleCells().map((cell) => (
              <Table.Cell key={cell.id}>
                {flexRender(cell.column.columnDef.cell, cell.getContext())}
              </Table.Cell>
            ))}
          </Table.Row>
        ))}
      </Table.Body>
    </Table>
  );
}

无障碍

语义化 HTML

表格使用语义化的 <table>、<thead>、<tbody>、<th> 和 <td> 元素,便于屏幕阅读器正确导航。

复选框标签

始终为 Table.CheckHead 和 Table.CheckCell 提供 aria-label,以说明其用途。

键盘导航

Tab 可在可交互元素之间移动焦点。复选框响应 Space。