mcpField
N
niko-table-best-practices

niko-table-best-practices

github.com/semkoo开发7280 次安装3 天前更新
代码仓库

关于 niko-table-best-practices

niko-table-best-practices 是帮助开发者使用 Niko Table 构建和配置数据表的技能。内容涵盖组件组合、筛选、拖放、服务端模式、URL 状态和可编辑网格,并根据具体任务提供指导。

主要功能

  1. 01推荐数据表组件结构
  2. 02配置搜索和高级筛选
  3. 03设置行列拖放
  4. 04指导服务端数据表状态
  5. 05将表格状态同步到 URL
  6. 06构建可编辑 Data Grid

适用场景

  1. 01创建带分页和筛选的数据表
  2. 02为数据表添加分组或拖放
  3. 03将表格查询连接到服务端
  4. 04构建类似电子表格的可编辑网格

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/semkoo/niko-table-registry --skill niko-table-best-practices

安装后在 Claude Code 中输入/niko-table-best-practices确认已加载。

详细介绍

Niko Table 集成指南

使用 Niko Table 构建和配置数据表格的技能:结构、筛选器(搜索、分面、高级筛选)、列菜单、拖放、服务端模式和可编辑数据网格。

概览:

  • 新建表格:DataTableRoot → ToolbarSection(可选)→ DataTable → Header + Body(Skeleton、EmptyBody)→ Pagination。仅使用直接文件导入(不要使用 barrel exports)。如果由你管理 TanStack 实例,请为所有者安装 @niko-table/data-table;按需使用的控件依赖 @niko-table/data-table-core(上下文 + 结构,不含 Root)。
  • 添加筛选器:工具栏 = DataTableSearchFilter、DataTableFacetedFilter、DataTableFilterMenu。列标题 = DataTableColumnFacetedFilterMenu、DataTableColumnSliderFilterMenu、DataTableColumnDateFilterMenu。设置列 meta(variant、options 等),并设置 enableColumnFilter: true。
  • 行/列拖放:行拖放需要 getRowId,并将 DataTableRowDndProvider 放在 DataTable 外部;不要将行拖放与排序/筛选结合使用。列拖放可安全地与所有功能结合使用。
  • 分组:在 DataTableColumnActions 中挂载 DataTableColumnGroupOptions(或设置 config.enableGrouping)。使用 aggregationFn / aggregatedCell 汇总数据,并使用 getGroupingValue 创建分组桶(例如按月)。不要与行拖放或树形 getSubRows 结合使用——树形表 = 嵌套数据;分组 = 按列分桶的平面行。请参阅 niko-table.com 上的 Grouping Table / Tree Table。
  • 服务端:设置 config.manualPagination / manualSorting / manualFiltering + config.pageCount,将 totalCount 传给 DataTablePagination,并在 DataTable 上设置 maxHeight,以便更改每页行数时可以滚动。围绕可序列化的传输契约构建结构——使用一个函数 fetch(query: { page, pageSize, sorting, search, columnFilters }) → { data, total, facets }——即可接入任何后端(SQL、Drizzle、Prisma、Supabase、REST);请参阅 niko-table.com 上的 Server-Side Table 示例和 Drizzle ORM 指南。
  • URL 状态(nuqs):使用 NuqsAdapter 包装应用;使用带解析器的 useQueryStates 管理分页、排序、筛选器和搜索;将 URL 派生的状态传入 DataTableRoot,并将 onPaginationChange / onSortingChange / onColumnFiltersChange / onGlobalFilterChange 连接到 setUrlParams。
  • 大型列表:对于 10k+ 行,请使用 DataTableVirtualizedBody(来自 core/structure)替代 DataTableBody;子项相同(Skeleton、EmptyBody)。请参阅 Virtualization Table 示例。
  • 侧边栏:使用 DataTableAside(及其触发器)在表格旁显示详情面板。请参阅 Aside Table 示例。
  • 数据网格:使用 useDataGrid + <DataGrid grid={grid}>,在 DataTableRoot 内包裹 DataTable。剪贴板/填充/移动功能需选择启用子项。通过 <DataGridCell> + Grid*Cell 设置单元格编辑器。安装 @niko-table/data-table-grid(持久化还需安装 data-table-grid-changes)。在网格内挂载 <DataTableColumnResize />,使列弹性填满宽度,并为 <DataGrid> 传入 className="space-y-2 outline-none" 以设置间距。对于由服务端提供数据的网格,不要分页——应在滚动时流式加载数据块(请参阅下文的服务端模式)。请参阅 niko-table.com 上的 Basic Grid / Data Grid 文档。

使用此技能时,你的任务是判断用户当前的需求——新建表格、添加筛选器/拖放/分组、修复导入、接入服务端、URL 状态(nuqs)、行展开、树形表格、行选择或可编辑数据网格——并提供合适的结构、导入方式和模式。如果用户描述含糊(“我想要一个表格”),请推荐最简模板,并引导其查看 niko-table.com 上的示例。如果用户已有表格,想添加分面筛选器或高级筛选菜单,请直接跳转到 Filtering 部分。如果用户想要电子表格编辑功能,请转到 Data Grid。灵活应对:有些用户想要可直接复制粘贴的代码片段;有些用户则想了解双层(DataTable* 与 Table*)模式。

完整文档和示例:**https://niko-table.com**。组件注册表:在 components.json 的 registries["@niko-table"] 中使用 https://niko-table.com/r/{name}.json。

快速参考

与用户沟通

用户可能刚接触 Niko Table 或 shadcn/TanStack 技术栈。如有疑问,请简要说明直接导入为何重要(可进行树摇优化,且无需使用 barrel 文件),以及行拖放(DnD)为何需要 getRowId。请说明,大多数 DataTableRoot 配置会根据他们使用的组件自动检测,因此只有在需要覆盖配置或使用手动/服务端模式时,才需要传入 config。如需深入参考(所有附加组件、完整 API),请指向 niko-table.com。

**不适用场景:**如果项目明显使用其他表格库(例如 AG Grid、MUI Data Grid,或未使用此注册表的 TanStack Table),不要强行推荐 Niko Table,而应建议适合其技术栈的模式。

表格结构

所有表格 UI 都必须位于 DataTableRoot 内。推荐的组合方式:

DataTableRoot (required)
  → DataTableToolbarSection (optional: search, filters, view menu)
  → DataTable
      → DataTableHeader
      → DataTableBody
          → DataTableSkeleton   (when loading)
          → DataTableEmptyBody  (when no data)
  → DataTablePagination (optional)

**可选:**将表格(或 DataTableRoot)包裹在来自 @/components/niko-table/core/data-table-error-boundary 的 DataTableErrorBoundary 中,这样渲染错误会显示回退 UI,而不会导致页面崩溃。

导入 — 不使用 Barrel 导出

仅使用直接文件路径。不要使用 core、components 或 filters 的 index.ts 重新导出。

用途导入路径
根组件和表格@/components/niko-table/core/data-table-root、@/components/niko-table/core/data-table
结构@/components/niko-table/core/data-table-structure(Header、Body、Skeleton、EmptyBody)
工具栏 / 筛选器@/components/niko-table/components/data-table-toolbar-section、data-table-search-filter、data-table-pagination 等。
类型@/components/niko-table/types(例如 DataTableColumnDef)

示例:

import { DataTableRoot } from "@/components/niko-table/core/data-table-root"
import { DataTable } from "@/components/niko-table/core/data-table"
import {
  DataTableHeader,
  DataTableBody,
  DataTableSkeleton,
  DataTableEmptyBody,
} from "@/components/niko-table/core/data-table-structure"
import { DataTableToolbarSection } from "@/components/niko-table/components/data-table-toolbar-section"
import { DataTableSearchFilter } from "@/components/niko-table/components/data-table-search-filter"
import { DataTablePagination } from "@/components/niko-table/components/data-table-pagination"
import type { DataTableColumnDef } from "@/components/niko-table/types"

双层组件模式

  • 组件(DataTable*):感知上下文;内部使用 useDataTable()。从 components/ 导入。常规使用时(无需 table 属性)优先选择这些组件。
  • 筛选器(Table*):接受 table 属性;从 filters/ 导入。构建自定义组件或自行管理表格实例时使用。

基于上下文使用时,从直接路径(例如 data-table-pagination)导入 DataTable* 组件;需要底层 API 时,使用 filters 中的 Table*。

列定义

  • 类型:来自 @/components/niko-table/types 的 DataTableColumnDef<TData>[]。
  • 使用 accessorKey 和 header。对于可排序/可筛选的列,请使用 DataTableColumnHeader、DataTableColumnTitle 和 DataTableColumnSortMenu(并按需使用列筛选菜单)。
  • 筛选配置使用 meta:label、placeholder、variant(text、select、multi_select、range、date、date_range、number、boolean)、options(静态 { label, value }[])、autoOptions(根据数据生成)、unit(例如范围筛选的 "$")、showCounts、dynamicCounts、mergeStrategy(针对选项的 "preserve" | "augment" | "replace")。使用列筛选器时,请设置 enableColumnFilter: true。

筛选

工具栏筛选器(位于 DataTableToolbarSection 内)
  • 全局搜索:DataTableSearchFilter — 单个搜索输入框;无需列 meta。
  • 高级筛选(基于规则):DataTableFilterMenu — 命令面板样式;可添加多个 AND/OR 筛选规则。列的 meta.variant(例如 text、select、range、date)决定筛选类型。安装 @niko-table/data-table-filter-menu,多选时还可选装 Shadcn 的 checkbox。
  • 分面筛选(内联):DataTableFacetedFilter — 每列一个筛选器;显示带计数的选项。使用 accessorKey 关联到某一列;选项来自列的 meta.options 或 meta.autoOptions。多选时使用 multiple。limitToFilteredRows 会将选项限制为当前结果集。
  • 其他工具栏筛选器:使用 DataTableSliderFilter、DataTableDateFilter 在工具栏中进行范围或日期筛选;使用 DataTableClearFilter 清除所有筛选器。
列级筛选菜单(位于表头中)

在列的 header 内,紧挨着 DataTableColumnTitle 和 DataTableColumnSortMenu 渲染:

  • 分面筛选:DataTableColumnFacetedFilterMenu — 带计数的单选/多选。列需要设置 meta.options 或 meta.autoOptions;可选设置 meta.showCounts、meta.dynamicCounts、meta.mergeStrategy。必要时,在 DataTableColumnSortMenu 上使用 FILTER_VARIANTS.TEXT(或 .NUMBER、.DATE)。
  • 滑块(范围):DataTableColumnSliderFilterMenu — 数值范围;列的 meta.variant: "range",可选设置 meta.unit。
  • 日期:DataTableColumnDateFilterMenu — 日期或日期范围;列的 meta.variant: "date" 或 "date_range"。

带分面筛选和排序的列示例:

import { DataTableColumnHeader, DataTableColumnTitle } from "@/components/niko-table/components/data-table-column-header"
import { DataTableColumnSortMenu } from "@/components/niko-table/components/data-table-column-sort"
import { DataTableColumnFacetedFilterMenu } from "@/components/niko-table/components/data-table-column-faceted-filter"
import { FILTER_VARIANTS } from "@/components/niko-table/lib/constants"

{
  accessorKey: "category",
  header: () => (
    <DataTableColumnHeader>
      <DataTableColumnTitle />
      <DataTableColumnSortMenu variant={FILTER_VARIANTS.TEXT} />
      <DataTableColumnFacetedFilterMenu multiple limitToFilteredRows={false} />
    </DataTableColumnHeader>
  ),
  meta: {
    label: "Category",
    options: categoryOptions,
    mergeStrategy: "augment",
    dynamicCounts: true,
    showCounts: true,
  },
  enableColumnFilter: true,
}

带搜索、分面筛选、高级筛选和清除按钮的工具栏示例:

<DataTableToolbarSection>
  <DataTableSearchFilter placeholder="Search..." />
  <DataTableFacetedFilter accessorKey="category" title="Category" options={categoryOptions} multiple />
  <DataTableFacetedFilter accessorKey="brand" limitToFilteredRows />
  <DataTableFilterMenu autoOptions dynamicCounts showCounts mergeStrategy="augment" />
  <DataTableViewMenu />
  <DataTableClearFilter />
</DataTableToolbarSection>

附加组件:data-table-search-filter、data-table-filter-menu、data-table-faceted-filter、data-table-clear-filter、data-table-slider-filter、data-table-date-filter、data-table-column-faceted-filter、data-table-column-slider-filter、data-table-column-date-filter。完整列表请访问 niko-table.com。

DataTableRoot 配置和状态

大多数配置会根据你渲染的组件自动检测:例如,DataTablePagination 会启用分页;DataTableSearchFilter / DataTableFilterMenu / DataTableFacetedFilter / 列筛选菜单会启用筛选;DataTableColumnHeader / DataTableColumnSortMenu 会启用排序;DataTableSelectionBar 会启用行选择。只有在需要覆盖默认值或启用子组件未声明的功能(例如服务端或手动模式)时,才需要传入 config。

  • config(按需覆盖):manualPagination、manualSorting、manualFiltering、pageCount、initialPageSize、initialPageIndex、autoResetPageIndex、autoResetExpanded,或用于关闭某项功能。完整列表:enablePagination、enableSorting、enableFilters、enableRowSelection、enableExpanding 等。
  • state:可选的受控 state,以及 onPaginationChange、onSortingChange、onColumnFiltersChange、onColumnVisibilityChange、onRowSelectionChange、onExpandedChange、onRowSelection。
  • getRowId:可选的 (row, index) => string。使用行拖放(DnD)、行选择或展开功能时,请使用稳定的唯一 ID(例如 (row) => row.id)——基于索引的默认 ID 会在重新排序后失效。
  • 加载状态:在 DataTableRoot 上设置 isLoading;在 DataTableBody 内渲染 DataTableSkeleton 和 DataTableEmptyBody。

URL 状态(nuqs)

将表格状态(分页、排序、筛选、搜索)与 URL 同步,以便分享和收藏视图。使用 nuqs:安装 nuqs,并在应用根节点使用对应框架的 NuqsAdapter 包裹应用(nuqs/adapters/next/app、nuqs/adapters/next/pages 或 nuqs/adapters/react)。有关设置方法,请参阅 nuqs adapters docs。

  • 解析器: 使用 parseAsInteger.withDefault(0) 为 pageIndex/pageSize 定义解析器,使用 parseAsJson 处理 sort/filters,使用 parseAsString 处理 search。匹配 TanStack Table 的状态结构,使 URL 参数与 state 一一对应。
  • 接线: useQueryStates(parsers, { history: "replace" }) → [urlParams, setUrlParams]。从 urlParams 派生 pagination、sorting、columnFilters、globalFilter(例如通过 useMemo)。将它们作为 state={{ pagination, sorting, columnFilters, globalFilter }} 传给 DataTableRoot。在 onPaginationChange、onSortingChange、onColumnFiltersChange、onGlobalFilterChange 中,调用 setUrlParams 并传入更新后的部分状态,以保持 URL 同步。
  • DataTableFilterMenu: 使用 nuqs 搭配筛选菜单时,URL 中的筛选条件通常以扩展筛选对象的形式存储;在处理函数中,使用 serializeFiltersForUrl / normalizeFiltersFromUrl(从 filters/table-filter-menu 导出)在 TanStack ColumnFiltersState 与该结构之间转换(它们会移除/重新生成 filterId,以缩短 URL 并保持输入焦点稳定)。请参阅 niko-table.com 上的 Advanced Nuqs Table 和 Server-Side Nuqs Table 示例。

安装(适用于未使用 Niko Table 的项目)

  1. 前置条件:React 项目、Shadcn UI、TailwindCSS、TypeScript。
  2. 客户端组件:表格组件使用 React 状态和 Hook;在任何渲染 DataTableRoot 或 Niko Table 组件的文件顶部添加 "use client"(Next.js App Router 等场景中必须添加)。
  3. 注册表:在 components.json 中添加:
    "registries": {
      "@niko-table": "https://niko-table.com/r/{name}.json"
    }
    
  4. 核心组件:shadcn@latest add @niko-table/data-table(会拉取 data-table-core + data-table-ui + Root/外观组件;安装/更新 components/ui/table.tsx,其中包含 TableComponent 和支持键盘聚焦的滚动容器)。如果只需要控件/自有 TanStack 实例:安装控件项即可——它们会解析 data-table-core,而不包含 Root 或 table.tsx。只有在需要我们的表格原语时才添加 @niko-table/data-table-ui。
  5. 附加组件(示例):@niko-table/data-table-pagination、@niko-table/data-table-search-filter、@niko-table/data-table-view-menu、@niko-table/data-table-sort-menu、@niko-table/data-table-filter-menu,以及按需添加列级筛选/排序组件。请使用 niko-table.com 注册表中的对应名称。
  6. 服务端:对于 manualPagination/manualSorting/manualFiltering,设置 config.pageCount(例如 Math.ceil(totalCount / pageSize));使用服务端驱动的数据时,将 totalCount 传给 DataTablePagination。

拖放

  • 行拖放: 不要与排序或筛选同时使用(数据顺序会冲突)。需要 getRowId={(row) => row.id}(或类似的稳定 ID)——重排后,基于索引的 ID 会失效。在 <DataTable> 外部使用 DataTableRowDndProvider 包裹(拖放上下文使用的 div 不能放在 <table> 内)。内部使用 DataTableDndBody 和 DataTableRowDragHandle。添加拖动手柄列:cell: ({ row }) => <DataTableRowDragHandle rowId={row.id} />。
  • 列拖放: 可以安全地与其他功能同时使用。使用 DataTableColumnDndProvider、DataTableDraggableHeader、DataTableDragAlongCell 以及对应的核心结构组件(需要时包括虚拟化变体)。

样式

使用语义化颜色令牌(例如 bg-success、text-destructive),不要使用硬编码的 Tailwind 颜色。

应避免的陷阱

  • 不要使用 barrel import:不要从 @/components/niko-table、.../core 或 .../components 导入;必须使用包含文件完整路径的导入(例如 .../core/data-table-root)。
  • 行拖放时未指定 getRowId:行拖放需要稳定的行 ID;请传入 getRowId={(row) => row.id}(或你的 ID 字段)。省略该项或使用索引会导致重新排序后行为错误。
  • 同时启用行拖放和排序/筛选:不要同时启用行重新排序和排序/筛选;数据顺序会变得模糊。
  • 将 DataTableRowDndProvider 放在 <table> 内部:Provider 必须从外部包裹整个 DataTable;其标记不能放入 <table> 内。

最简表格模板

"use client"

import { DataTableRoot } from "@/components/niko-table/core/data-table-root"
import { DataTable } from "@/components/niko-table/core/data-table"
import {
  DataTableHeader,
  DataTableBody,
  DataTableSkeleton,
  DataTableEmptyBody,
} from "@/components/niko-table/core/data-table-structure"
import { DataTableToolbarSection } from "@/components/niko-table/components/data-table-toolbar-section"
import { DataTableSearchFilter } from "@/components/niko-table/components/data-table-search-filter"
import { DataTablePagination } from "@/components/niko-table/components/data-table-pagination"
import type { DataTableColumnDef } from "@/components/niko-table/types"

type User = { id: string; name: string; email: string }

const columns: DataTableColumnDef<User>[] = [
  { accessorKey: "name", header: "Name" },
  { accessorKey: "email", header: "Email" },
]

export function UsersTable({ data, isLoading }: { data: User[]; isLoading?: boolean }) {
  return (
    <DataTableRoot data={data} columns={columns} isLoading={isLoading}>
      <DataTableToolbarSection>
        <DataTableSearchFilter placeholder="Search..." />
      </DataTableToolbarSection>
      <DataTable>
        <DataTableHeader />
        <DataTableBody>
          <DataTableSkeleton />
          <DataTableEmptyBody />
        </DataTableBody>
      </DataTable>
      <DataTablePagination />
    </DataTableRoot>
  )
}

数据网格

基于同一 DataTableRoot/虚拟化主体构建的可编辑电子表格样式网格。不要另行设计独立的组件 API。

DataTableRoot data={grid.rows} getRowId={(r) => r.id}
  → DataGrid grid={grid}
      → opt-in: DataGridClipboard, DataGridFillHandle, DataGridMove, …
      → DataTable → VirtualizedHeader + VirtualizedBody (fixed height)
  • 引擎:useDataGrid({ columnIds, createEmptyRow, initialRows? }) — 非受控行,按 { rowId, columnId } 管理焦点/选中状态,支持撤销/重做。
  • **单元格:**使用 <DataGridCell row={…} columnId={…}> 包裹编辑器。可使用 GridTextCell、GridNumberCell、GridCheckboxCell、GridDateCell、GridSelectCell/GridComboboxCell。有效性由你的 resolve → CellState 决定。
  • **可选功能:**仅作为 <DataGrid> 的子项挂载 — 未挂载的功能会被 tree-shaken。
  • **持久化:**单独安装 @niko-table/data-table-grid-changes → useGridChanges(grid, { initialRows })。
  • **服务端网格:**不使用分页 — 通过 DataTableVirtualizedBody 的 onNearEnd + prefetchThreshold 在滚动时流式加载行。使用 grid.updateRows(() => rows, { history: false }) + changes.reset(rows) 加载每个数据块,并在 changes.dirtyRowIds 周围合并数据,以保留未保存的编辑。通过 changes.getChangeSet() → POST { created, updated, deleted } → changes.reconcile({ succeededIds, failedIds }) 保存;失败的行会保持脏状态(使用 failedRowIds 高亮)。将 useDataGrid 的 maxRows(默认值为 200)调高至预期加载行数以上。请参阅 Server-Side Grid 示例。
  • **文档:**https://niko-table.com/data-grid/introduction/ · https://niko-table.com/examples/basic-grid/

了解更多

  • **在线:**https://niko-table.com — 安装、示例、组件概览、API。表格示例:Simple / Basic / Faceted / Advanced / Nuqs / Server-Side / Server-Side Nuqs / Infinite Scroll / Row DnD / Column DnD / Virtualization / Aside;Drizzle ORM 指南(包含展示生成 SQL 的实时模拟演示)实现了服务端线协议。数据网格示例:Basic Grid、Cell Types、Validation、Dynamic Columns、Persistence、Server Side。增强稳定性:DataTableErrorBoundary(core/data-table-error-boundary)。
  • **技能(AI):**https://niko-table.com/getting-started/skills/ — 了解如何安装和使用此技能。
  • **文档指南:**https://niko-table.com/contributing/documentation-guidelines/
  • 仓库内(在 niko-table-registry 中工作时):src/content/docs/ — 例如 getting-started/installation.mdx、niko-table/overview/、data-grid/overview/、examples/*-table.mdx、examples/*-grid.mdx。

评论

支持 Markdown