跳转到内容

Table 表格 ​

多行同构记录按列排开,支持排序、选择、展开与吸顶。

用法 ​

columns 是列号与列宽的唯一事实源,rows 是行序与行号的唯一事实源,标记只负责外观;列名装在 column-label 里,它是列头里唯一可收窄的一格,排序与列宽把手写在它旁边

团队成员
姓名
部门
职级
赵一
平台研发
P6
钱二
前端体验
P7
孙三
基础架构
P6
李四
质量保障
P5

组件结构 ​

加粗的是必需部件。

data-scope="table":root · header · body · footer · row · column-header · column-label · cell · caption · toolbar · column-list · column-visibility-trigger · select-all-trigger · row-select-trigger · sort-trigger · column-resize-trigger · column-drag-trigger · row-drag-trigger · expand-trigger · expanded-row · empty · loading · load-more-trigger · live-region

示例 ​

排序 ​

列上标注 sortable 才识别排序按钮;按住 Shift 点击是追加到排序链,直接点击是整条链换为该列

姓名
部门
职级
赵一
平台研发
P6
钱二
前端体验
P7
孙三
基础架构
P6
李四
前端体验
P5
排序链:(无)

多选 ​

selectionMode 默认 none,声明 multiple 才有选择机制;选择列也要在 columns 中占一条,否则右侧列号错位

姓名
部门
赵一
平台研发
钱二
前端体验
孙三
基础架构
李四(禁用)
质量保障
选中:u2

行展开 ​

行上标注 expandable 才识别展开按钮与左右方向键;详情行占一个真实行号,收起只加 hidden 不卸载内部节点

订单号
金额
XH-2026-0001
¥ 1,280
明细:键盘 ×1、鼠标 ×2
明细:显示器支架 ×1
明细:线材若干
展开:o1

密度 ​

size 只写为 root 的 data-size,改变的是单元格纵向内边距与字号;三档并排,差别在行高上

sm 紧凑
姓名
职级
赵一
P6
钱二
P7
孙三
P6
李四
P5
周五
P7
缺省
姓名
职级
赵一
P6
钱二
P7
孙三
P6
李四
P5
周五
P7
lg 宽松
姓名
职级
赵一
P6
钱二
P7
孙三
P6
李四
P5
周五
P7

空态与加载态 ​

两个状态节点常驻只依靠 hidden 显隐:表体为空且在取数时显示加载态,取数完成后没有行才显示空态

任务
负责人
还没有任务,点「取数」拉一份。

脚注合计 ​

footer 把行号空间的最后一行留给脚注;脚注单元格不属于任何数据行,也就没有选中与禁用

采购清单
条目
数量
金额
键盘
2
¥ 1280
鼠标
3
¥ 447
显示器支架
1
¥ 320
合计
6
¥ 2047

表头吸顶与列吸附 ​

root 自身就是滚动容器:stickyHeader 固定表头,列上标注 sticky 的固定该列

姓名
部门
城市
分机
邮箱
员工 1
平台研发
杭州
8100
member1@example.com
员工 2
前端体验
上海
8101
member2@example.com
员工 3
基础架构
北京
8102
member3@example.com
员工 4
质量保障
成都
8103
member4@example.com
员工 5
平台研发
杭州
8104
member5@example.com
员工 6
前端体验
上海
8105
member6@example.com
员工 7
基础架构
北京
8106
member7@example.com
员工 8
质量保障
成都
8107
member8@example.com
员工 9
平台研发
杭州
8108
member9@example.com
员工 10
前端体验
上海
8109
member10@example.com
员工 11
基础架构
北京
8110
member11@example.com
员工 12
质量保障
成都
8111
member12@example.com
员工 13
平台研发
杭州
8112
member13@example.com
员工 14
前端体验
上海
8113
member14@example.com
员工 15
基础架构
北京
8114
member15@example.com
员工 16
质量保障
成都
8115
member16@example.com

单选 ​

selectionMode 设为 single:选中集合最多一个元素,再次点击已选中的行即清空,焦点行按空格同理

套餐
价格
入门版
¥ 0 / 月
团队版
¥ 99 / 月
企业版
¥ 399 / 月
已选:p2

跨列单元格 ​

colspan 从它自己的列向后计算,报告为 aria-colspan;1 与省略同义,因此只在真正跨列时写

交付单量
小组
上半年
下半年
平台研发
42
51
前端体验
36
39
全年
168

单元格就地编辑 ​

表体的方向键与 Home/End 是挂在 body 上的冒泡监听,可编辑控件上阻止冒泡后这些键就回归输入框自身

采购清单
条目
数量
备注
键盘
鼠标
显示器支架
合计 6 件

多行表头与表头分组 ​

表头写几行就是几行;分组格的跨列数与两行表头的行号由标记声明,columns 仍只登记叶子列

季度交付单量
上半年
下半年
小组
Q1
Q2
Q3
Q4
平台研发
12
15
18
21
前端体验
9
11
14
16
基础架构
7
8
10
12

列过滤 ​

过滤按钮是列标题中的一段内容,过滤结果就是宿主计算后传入的 rows;表头是表体的兄弟,按钮上的按键不会被表体接管

姓名
部门
城市
赵一
平台研发
杭州
钱二
前端体验
上海
孙三
基础架构
北京
李四
前端体验
杭州
周五
质量保障
成都
吴六
平台研发
上海
命中 6 / 6 人 · 部门:不限 · 城市:不限

树形表格 ​

rows 按契约就是一条已摊平的可见行序列:层级三项逐行声明,缩进落在首格的内边距上

组织
负责人
研发中心
赵一
服务端组
周五
展开:rd

拖拽调整列宽 ​

列上标注 resizable 才识别改宽把手;拖出表头仍跟随,方向键一次 8px、按住 Shift 一次 40px

拖动列标题右侧那条竖线;也可以 Tab 到它用方向键调
姓名
部门
城市
赵一
平台研发
杭州
钱二
前端体验
上海
孙三
基础架构
北京
李四
质量保障
成都
列宽偏好:{}

只渲染窗口内的行 ​

全量 rows 照常交给 root(那只是行序与行号的元信息,不产生 DOM),标记中只渲染可见的一段,首尾用两块空白撑出真实滚动高度

编号
姓名
部门
#1
员工 1
平台研发
#2
员工 2
前端体验
#3
员工 3
基础架构
#4
员工 4
质量保障
#5
员工 5
平台研发
#6
员工 6
前端体验
#7
员工 7
基础架构
#8
员工 8
质量保障
#9
员工 9
平台研发
#10
员工 10
前端体验
#11
员工 11
基础架构
#12
员工 12
质量保障
#13
员工 13
平台研发
#14
员工 14
前端体验
#15
员工 15
基础架构
#16
员工 16
质量保障
#17
员工 17
平台研发
#18
员工 18
前端体验
共 2000 行,此刻在 DOM 里的是第 1 – 18 行

放进滚动区 ​

表格交给滚动区的视口滚动,两条自绘滚动条与吸顶表头、吸附列一起工作;表格自身不再定高

姓名
部门
城市
分机
邮箱
员工 1
平台研发
杭州
8100
member1@example.com
员工 2
前端体验
上海
8101
member2@example.com
员工 3
基础架构
北京
8102
member3@example.com
员工 4
质量保障
成都
8103
member4@example.com
员工 5
平台研发
杭州
8104
member5@example.com
员工 6
前端体验
上海
8105
member6@example.com
员工 7
基础架构
北京
8106
member7@example.com
员工 8
质量保障
成都
8107
member8@example.com
员工 9
平台研发
杭州
8108
member9@example.com
员工 10
前端体验
上海
8109
member10@example.com
员工 11
基础架构
北京
8110
member11@example.com
员工 12
质量保障
成都
8111
member12@example.com
员工 13
平台研发
杭州
8112
member13@example.com
员工 14
前端体验
上海
8113
member14@example.com
员工 15
基础架构
北京
8114
member15@example.com
员工 16
质量保障
成都
8115
member16@example.com
员工 17
平台研发
杭州
8116
member17@example.com
员工 18
前端体验
上海
8117
member18@example.com
员工 19
基础架构
北京
8118
member19@example.com
员工 20
质量保障
成都
8119
member20@example.com
员工 21
平台研发
杭州
8120
member21@example.com
员工 22
前端体验
上海
8121
member22@example.com
员工 23
基础架构
北京
8122
member23@example.com
员工 24
质量保障
成都
8123
member24@example.com

前缀列与分页序号 ​

prefix-columns 让库把序号/多选列插在最前面并占用列号;序号是分页全局序号,翻到第二页不会重新从 1 开始

#
名称
负责人
状态
1
资源 1
曦寒
停用
2
资源 2
碧落
启用
3
资源 3
葳蕤
启用
4
资源 4
曦寒
启用
5
资源 5
碧落
停用
6
资源 6
葳蕤
启用
7
资源 7
曦寒
启用
8
资源 8
碧落
启用
9
资源 9
葳蕤
停用
10
资源 10
曦寒
启用
已选 0 项 · 序号跨页连续

范围选择 ​

按住 Shift 点击勾选框选中一段;焦点落在表体中按 Ctrl/Cmd + A 全选。禁用行占据顺序位置但不被选入

点第一行的勾选框,再按住 Shift 点第五行 —— 中间整段一起选上(禁用那行跳过)。 再按住 Shift 点第三行,选区会往回收,起点不变。 焦点落在表体里按 Ctrl/Cmd + A 全选。

文件名
大小
报告.docx
1.2 MB
预算.xlsx
480 KB
会议纪要.md
12 KB
归档.zip(禁用)
88 MB
封面.png
2.4 MB
演示.pptx
5.1 MB
选中:(无)

拖拽调整列位 ​

列上标注 reorderable 才识别拖拽把手;也可以 Tab 到它用方向键移动,Home / End 到两端

拖列标题左侧的抓手换位;「操作」列没标 reorderable,拖不动也拖不过去
姓名
部门
城市
操作
赵一
平台研发
杭州
编辑
钱二
前端体验
上海
编辑
孙三
基础架构
北京
编辑
列序:(还没改过)

拖拽调整行位 ​

整行都是拖动源,按住拖到目标位置松手;也可以 Tab 进表体后按 Alt + 上下键移动。库只报告新行序,写回归使用者

按住任意一行拖动换位,落点画在两行之间;也可以 Tab 进表体,用 Alt + 上下键挪
序号
环节
负责人
1
需求评审
赵一
2
方案设计
钱二
3
开发实现
孙三
4
测试验收
李四
5
发布上线
周五
当前顺序:需求评审 → 方案设计 → 开发实现 → 测试验收 → 发布上线

触屏拖动把手 ​

整行拖动只识别鼠标与笔;触屏要按住行首的把手才能拖动,代价是该小块区域不再随表格滚动。键盘路径照常:Tab 进表体后 Alt + 上下键

鼠标按住整行就能拖;手机上按住行首的抓手拖,按下即走,不用先拖一段距离
序号
环节
负责人
1
需求评审
赵一
2
方案设计
钱二
3
开发实现
孙三
4
测试验收
李四
5
发布上线
周五
当前顺序:需求评审 → 方案设计 → 开发实现 → 测试验收 → 发布上线

树形表拖拽 ​

行声明了 parentId 即为树:拖到一行中段是放进该行(更换父节点),拖到上下两端仍是插在它前后;键盘使用 Alt + 上下键同层移动、Alt + 左右键改变缩进。库报告的是移动到哪个父节点下的第几位外加重排后的整份行序,写回归宿主:按 ids 重排、再把该行的 parentId 设为 parent,两件都做才一致。是否允许移动由 allowRowDrop 决定

拖到一行中段是放进这一行,拖到上下两端是插在它前后;也可以 Tab 进表体,用「Alt + 上下键」同层挪、「Alt + 左右键」改缩进。已归档那一组只出不进
任务
负责人
客户端
赵一
登录页改版
钱二
离线缓存
孙三
服务端
李四
限流中间件
周五
已归档
吴六
旧版导出
郑七
按住任意一行拖走,或 Tab 进表体按 Alt + 方向键搬

列设置与工具条 ​

工具条渲染为表的兄弟排在表前(root 是 grid,工具条不能进入其中);列设置区按 columnSettings 渲染,隐藏的列也在其中,只剩最后一列显示时该按钮转为禁用

成员 4 人
姓名
部门
城市
职级
赵一
平台研发
杭州
P6
钱二
前端体验
上海
P7
孙三
基础架构
北京
P6
李四
前端体验
杭州
P5
存下来的列偏好:尚未改过

设计指引 ​

何时使用 ​

  • 每条记录有多个字段需要按列对照。
  • 需要排序、筛选、批量选择。

何时不用 ​

  • 每条只有标题和一句描述时,使用列表,表格的列头是额外负担。
  • 移动端窄屏上横向滚动的表格难以使用,考虑换成卡片列表。

特性 ​

  • 排序、选择、展开三套状态各自可受控。
  • 列名放在 column-label 里,它是列头里唯一可收窄的一格:列名太长时由它出省略号。排序钮、列宽把手与列拖拽把手都是它的兄弟,不装进它里面。列头是 flex 行,裸写的文本是匿名 flex item、缩不下去,窄列上会把定尺的把手连同外边距一起挤出列头盒,所以不可排序、不可改宽的列也要用它。
  • 排序钮(sort-trigger)是列头里独立的定尺图标钮,不包列名:列名留在 column-label 上,钮写在列名之后、被推到行尾侧与列宽把手并排;点列头文字不排序,点钮才排序。
  • 选中行铺品牌淡底行面并由行首的勾选方框标记;悬停与按下只换面,行的几何与吸附列不动。
  • 表头吸顶与列吸附、条纹、密度、边框都是开关。
  • 支持多行表头与表头分组、跨列单元格、树形表格、单元格就地编辑、列过滤、拖拽调列宽。
  • 行数很大时只渲染窗口内的行。
  • 工具条(toolbar)与列设置区(column-list + column-visibility-trigger)把排序、列宽与显隐接出:设置区按 columnSettings 渲染,隐藏的列也包含在内。两块都放在 root 之外:root 是 grid 系角色,子节点只能是行与行组。
  • 三种非条目相位各有部件:空(empty)、在途(loading)、还有更多(load-more-trigger)。取下一页按钮的行为由作者决定,取数在途时自动停用。

组合 ​

最佳实践 ​

  • 列宽尽量固定,不让内容长度决定列宽,否则翻页时整张表会重排。
  • 批量选择要显示已选条数,并在跨页时说明选中范围。

反模式 ​

  • 列多到必须横向滚动却不吸附首列,滚动后无法分辨行。
  • 用表格做页面布局。

API 参考 ​

产物 ​

层值
自定义元素<xh-table>
Vue 组件XhTableBody XhTableCaption XhTableCell XhTableColumnDragTrigger XhTableColumnHeader XhTableColumnLabel XhTableColumnList XhTableColumnResizeTrigger XhTableColumnVisibilityTrigger XhTableEmpty XhTableExpandTrigger XhTableExpandedRow XhTableFooter XhTableHeader XhTableLoadMoreTrigger XhTableLoading XhTableRoot XhTableRow XhTableRowDragTrigger XhTableRowSelectTrigger XhTableSelectAllTrigger XhTableSortTrigger XhTableToolbar
组合式函数useTable
状态机tableMachine
皮肤@xihan-ui/styles/table.css

Props ​

属性类型必填说明
columnsTableColumnDef[]列定义,列号与列总数的唯一事实源。默认为空表。
rowsTableRowDef[]行定义,行序与行号的唯一事实源。默认为空表。
sortTableSortDescriptor[]排序链。提供即受控:cell 直读 prop,写入只发 onSortChange 不落内部值。
defaultSortTableSortDescriptor[]
selectionTableSelection选中集合。提供即受控,语义同上。
defaultSelectionTableSelection
expandedValuestring[]展开集合。提供即受控,语义同上。
defaultExpandedValuestring[]
selectionModeTableSelectionMode默认 none:未声明则没有选择机制,行也不报告 aria-selected。
prefixColumnsTableColumnKind[]需要的前缀列,按给定顺序插在最前面,默认不插入任何列。 它们由库插入并占用列号:不占用时右侧所有列的 aria-colindex 会整体错位, 这正是使用者手工向 columns 中添加假列的原因。作者按 api.columns 渲染即可, 每一项都声明 kind。
columnPreferenceTableColumnPreference列偏好。提供即受控:内部不自行修改,写入只发 onColumnPreferenceChange。 持久化归使用者:库只负责把它计算进生效列。
defaultColumnPreferenceTableColumnPreference
pagenumber当前页码与每页条数,只用于计算序号,不参与切片:切片归调用方 (或分页组件的 api.slice)。都未提供时序号回退为可见序。
pageSizenumber
loadingboolean数据加载中:root 报告 aria-busy,表体为空时加载态节点显示。
emptyboolean显式声明表体为空;未提供时按 rows 是否为空推导。
stickyHeaderboolean表头吸顶:只写 data-fixed(布尔),固定的实现归皮肤。列冻结使用 data-frozen,两者不同名。
stripedboolean斑马纹:表体偶数行换一层浅底。
variantControlVariant形态:outline 画外框与圆角(默认),ghost 去掉外框只留行间横线,subtle 淡底。默认 outline。
ruledboolean列与列之间加竖分隔线,写为 root 上的 data-split。
footerboolean表格带脚注行。行号空间的最后一行留给它,aria-rowcount 也把它计入。
loopboolean上下键到达首尾是否回绕,默认 false。
dirDirection文字方向,默认 ltr;只对调左右方向键的展开 / 收起语义。
sizeSize密度:sm / md / lg。只影响单元格的纵向内边距与字号,列宽算法不受影响。
translationsPartial<TableTranslations>
rowReorderableboolean行可以拖动换位。整行都是拖动源;另有一个不占 Tab 位的拖动把手, 触屏路径只经它(见 getRowDragTriggerProps)。
onRowMove(details: TableRowMoveDetails) => void
allowRowDrop(move: TableRowMoveDetails) => boolean本次移动是否允许。收到的是折算后的落点。 未提供时全部允许:落进自身后代与落在禁用行上两条由库自行拦截。
onColumnPreferenceChange(details: TableColumnPreferenceChangeDetails) => void
onSortChange(details: TableSortChangeDetails) => void
onSelectionChange(details: TableSelectionChangeDetails) => void
onExpandedValueChange(details: TableExpandedValueChangeDetails) => void

TableColumnDef ​

columns 的元素。

字段类型必填说明
idstring是全表唯一:既是 DOM 身份(data-value),也是排序链与列号索引的键。
labelstring展示名。只供调用方渲染,不作为可及名。
sortableboolean可排序:提供后才产出 aria-sort,排序把手也才响应按键与点击。
stickyboolean | 'start' | 'end'横向冻结(左右滚动时该列固定),写为条目上的 data-frozen。true 等于 'start'(固定在行首侧),'end' 固定在行尾侧。 与表头吸顶的 data-fixed 是两件事:那是布尔,这个带方向,同名会使 [data-fixed] 一条选择器命中两种语义。 同侧有多列吸附时,连接层按前面各列的数字列宽累加出偏移,写入 --xh-table-sticky-inset; 有一列宽度不是数字时无法计算,该侧从该列起都回退为贴边。
widthstring | number列宽。数字按 px 处理,字符串原样写入内联 inline-size。
minWidthnumber拖动改列宽时的下限(px)。未提供时使用 TABLE_COLUMN_MIN_WIDTH。
maxWidthnumber拖动改列宽时的上限(px)。未提供时不封顶。
resizableboolean该列的宽度可以拖动修改。提供后才产出改宽把手。
reorderableboolean该列可以拖动换位。提供后才产出拖拽把手:每个把手都是一个 Tab 位, 未声明的表格不承担该代价。 不可拖动的列与冻结列一样是屏障:跨过它落下会把它挤走,而作者已声明该列不动。

TableRowDef ​

rows 的元素。

字段类型必填说明
idstring是全表唯一:DOM 身份(data-value)、选中 / 展开集合的元素、连接层查询行的键。
disabledboolean行禁用:不可选中也不可展开,但仍可聚焦、仍是方向键的起点,也不计入全选基数。
expandableboolean可展开:提供后才报告 aria-expanded,左右方向键与展开把手也才识别该行。 只要有一行提供,root 就从 role=grid 改为 role=treegrid。
parentIdstring父行 id。提供后该行即为该父行的子行,收起父行时它随之隐藏。 有子行的行不再产出详情行:一行不可能同时既展开出子行、又展开出一块详情。 指向不存在的父行时按根行处理,不丢弃该行。

TableSortDescriptor ​

sort 的元素。

字段类型必填说明
idstring是
directionTableSortDirection是

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
sort-changeTableSortChangeDetails排序链变化;detail 为 { value: { id, direction }[] }
column-preference-change``列偏好变化;detail 为 { value: TableColumnPreference }
selection-changeTableSelectionChangeDetails选中集合变化;detail 为 { value: string[] | 'all' }
expanded-value-changeTableExpandedValueChangeDetails展开集合变化;detail 为 { value: string[] }
row-moveTableRowMoveDetails行换位;detail 为 { id, parent, index, ids },parent 为 null 即根层,index 是在该层的落位(已经过先移除后插入的修正),ids 是重排后的整份行序

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhTableRootdefaultTableRootSlotProps
XhTableRoottoolbarTableToolbarSlotProps工具条槽:搜索、筛选、密度与列设置等作用于整张表的控件写在这里。 它渲染为 root 的兄弟排在表前:root 是 grid 系角色,子节点只能是 row 与 rowgroup。

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhTableCellvaluestring是列 id。
XhTableCellcolspannumber | string跨列数,从 value 所在列向后计算。
XhTableColumnHeadervaluestring是
XhTableColumnVisibilityTriggervaluestring列 id。写在列设置区中时必须提供;写在列标题中时可省略,跟随该列。
XhTableExpandedRowvaluestring是所属数据行的 id。
XhTableRoottoolbarSlotChildren<TableToolbarSlotProps>工具条槽:搜索、筛选、密度与列设置等作用于整张表的控件写在这里。 它渲染为 root 的兄弟排在表前:root 是 grid 系角色,子节点只能是 row 与 rowgroup。
XhTableRootchildrenSlotChildren<TableRootSlotProps>
XhTableRowvaluestring行 id:数据行必须提供,表头行与脚注行省略。

状态 ​

公开状态写入 data-state。

部件取值
row'open' | 'closed' | undefined
column-visibility-trigger'unchecked' | 'checked'
select-all-triggertableSelectionState(selection, selectableIds)
row-select-trigger'open' | 'closed' | undefined
expand-trigger'open' | 'closed' | undefined
expanded-row'open' | 'closed'

以下名称仅用于内部状态机。

状态:idle · resizing · columnDragging · rowDragging

事件:SORT.SET · SORT.TOGGLE · COLUMN_PREF.SET · COLUMN_RESIZE.START · COLUMN_RESIZE.MOVE · COLUMN_RESIZE.END · COLUMN_RESIZE.CANCEL · COLUMN_RESIZE.STEP · COLUMN_DRAG.START · COLUMN_DRAG.MOVE · COLUMN_DRAG.END · COLUMN_DRAG.CANCEL · COLUMN.MOVE_BY · ROW_DRAG.START · ROW_DRAG.MOVE · ROW_DRAG.END · ROW_DRAG.CANCEL · ROW.MOVE_BY · ROW.REORDER_BLOCKED · COLUMN_PREF.PATCH · SELECTION.SET · ROW.SELECT · SELECTION.ALL_TOGGLE · EXPANDED.SET · ROW.EXPAND · ROW.COLLAPSE · ROW.EXPAND_TOGGLE · ROW.FOCUS · TABLE.BLUR · PRESS.START · PRESS.END

判据:canPress

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
columnsreadonly TableColumn[]生效的列:前缀列在前、数据列在后,各自声明 kind。 列号、渲染顺序都以它为准;不需要前缀列时它与作者提供的一致。
draggableColumnsreadonly string[]可以拖动换位的列 id 段。声明了 reorderable、不是冻结列、且彼此相连。 冻结列与不可拖动的列是屏障,把可拖动范围切分为段;这里给出的是最长的一段。 用它决定是否渲染把手,与库内部判定能否落下的口径是同一份。
rowReorderDisabledReasonTableRowReorderReason | null行不可拖动的原因,可拖动时为 null。声明了 rowReorderable 才可能非空。 库不自行弹出提示:是否把原因显示给用户由使用者决定。
dropTargetTableDropTarget | null当前的落点;松手即落在此处。没有合法落点时为 null,指示线随之消失。
announcementstring读屏播报文本。渲染进 live-region,不进入视觉版面。
rowsreadonly TableRowDef[]作者提供的行定义。
visibleRowsreadonly TableVisibleRow[]展开展平后的可见行序列(详情行插在所属数据行之后)。
sortTableSortDescriptor[]
selectionTableSelection
selectionStateTableSelectionState全选把手的三态,只按可选行(未禁用)计算。
selectionModeTableSelectionMode
expandedValuestring[]
focusedRowstring | null焦点锚点;焦点不在表体中时为 null。
loadingboolean
emptyboolean表体为空(显式声明或 rows 为空)。
rowCountnumberaria-rowcount:表头行 + 可见行 + 脚注行。
columnCountnumberaria-colcount:列定义的条数。
isSelected(value: string) => boolean
isExpanded(value: string) => boolean
sortDirection(value: string) => TableSortDirection | null该列当前的排序方向;不参与排序时为 null。
sortPriority(value: string) => number该列在排序链里的优先级,1 起算;不参与排序时为 0。
setSort(next: TableSortDescriptor[]) => void
toggleSort(value: string, options?: { append?: boolean }) => void
setSelection(next: TableSelection) => void
selectRow(value: string, options?: { extend?: boolean }) => void选中某一行。extend 为真时选中锚点到该行的范围(仅复选)。
toggleSelectAll() => void
setExpandedValue(next: string[]) => void
expandRow(value: string) => void
collapseRow(value: string) => void
toggleExpandRow(value: string) => void
getRootProps() => T['element']
getCaptionProps() => T['element']
getToolbarProps() => T['element']工具条:搜索、筛选、密度与列设置这些作用于整张表的控件放置在此。 它是 root 的兄弟不是子节点:root 是 grid 系角色,子节点只能是 row 与 rowgroup。 不提供 role:一条控件带是否需要 role=toolbar(连同该套方向键 roving)由作者决定, 需要时向其中放置一个 Toolbar 组件。
getColumnListProps() => T['element']列设置区:一列一行,行中放显隐把手、列名与作者自行编写的宽度 / 冻结 / 排序控件。 渲染内容按 columnSettings。
getColumnVisibilityTriggerProps(props: TableColumnProps) => T['element']一列的显隐把手(复选形态)。最后一列显示时它为 aria-disabled。
getHeaderProps() => T['element']
getBodyProps() => T['element']
getFooterProps() => T['element']
getHeaderRowProps() => T['element']表头行:恒占行号空间的第 1 行。
getFooterRowProps() => T['element']脚注行:占行号空间的最后一行。
rowNumber(rowId: string) => string该行显示的序号。平表是分页全局序号,树形是大纲编号。 不显示序号列时仍可调用:它是纯计算,不依赖是否有该列。
columnPreferenceTableColumnPreference当前的列偏好。原样交出即可存储。
columnSettingsreadonly TableColumnSetting[]列设置区按它渲染:作者定义的列,按偏好排序,隐藏的也在其中。 每条自带显隐、冻结、宽度与排序,足以渲染一整行设置项而不必回头比对两份数组。
setColumnHidden(columnId: string, hidden: boolean) => void隐藏 / 显示一列。
setColumnSticky(columnId: string, sticky: boolean | 'start' | 'end') => void修改一列的冻结档。false 为不冻结,true 等于 'start'。
moveColumn(columnId: string, toIndex: number) => void把一列移到某个位次(只在作者定义的列之间计算,0 起算)。
setColumnWidth(columnId: string, width: number | string) => void修改一列的宽度。
setColumnPreference(next?: TableColumnPreference) => void整份偏好替换;未提供时清空,回到作者定义的原样。
getRowProps(props: TableRowProps) => T['element']
getColumnHeaderProps(props: TableColumnProps) => T['element']
getColumnLabelProps() => T['element']列名。列头里唯一可收窄的一格:排序钮、列宽把手与列拖拽把手都是它的兄弟, 列名太长时由它出省略号,把手不会被挤出列头。只投部件属性,不带状态。
getCellProps(props: TableCellProps) => T['element']
getSelectAllTriggerProps() => T['element']
getRowSelectTriggerProps(props: TableRowProps) => T['element']
getSortTriggerProps(props: TableColumnProps) => T['element']排序钮。独立的定尺图标钮,排在列名之后;列名留在 column-header 上, 钮的可及名取 translations.sort(列名)。只有 sortable 的列才渲染它。
getColumnResizeTriggerProps(props: TableColumnProps) => T['element']列宽把手。只有 resizable 的列才渲染它。
getColumnDragTriggerProps(props: TableColumnProps) => T['element']列拖拽把手。只有 reorderable 的列才渲染它。
getRowDragTriggerProps(props: TableRowProps) => T['element']行拖动把手。触屏路径唯一的入口,不占 Tab 位。 常驻即可:rowReorderable 关闭或该表不可拖动时它声明 data-disabled、也不再让出滚动, 渲染不会出错。按是否可拖动决定是否渲染,会使 DOM 结构随状态变化。
getExpandTriggerProps(props: TableRowProps) => T['element']
getExpandedRowProps(props: TableRowProps) => T['element']
getEmptyProps() => T['element']
getLoadingProps() => T['element']
getLoadMoreTriggerProps() => T['element']取下一页的入口:是否还有下一页、点击后的行为都由作者决定, 连接层只保证取数在途期间不可点击。
getLiveRegionProps() => T['element']拖动过程的读屏播报区。视觉隐藏,文本取自 announcement。 它必须在拖动开始之前就在 DOM 上:读屏不播报后插入的节点。

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
Enter / Spaceheld on 可按部件, 未加载且部件自身未禁用按住期间行、全选 / 行选 / 展开 / 列显隐把手、排序把手或取下一页按钮投影 data-pressed,与指针 :active 同一副按压面;抬起或失焦撤下,取数在途由机器撤下。选中、排序与展开语义照旧由这一次按键承担
Tab / Shift+Tabfocus outside the table body表体只占一个 Tab 位:焦点进入锚点行,无锚点时先落 body 再由它转投;再按一次 Tab 整体离开表体
ArrowDownfocus in table body焦点移到下一个可见数据行(禁用行跳过;详情行不是落点;loop 默认关,末行不回绕)
ArrowUpfocus in table body焦点移到上一个可见数据行(禁用行跳过;loop 默认关,首行不回绕)
Homefocus in table body焦点移到首个可见数据行
Endfocus in table body焦点移到末个可见数据行
Spacefocus on row, selectionMode 非 none 且该行未禁用切换焦点行的选中(单选替换、复选增删);选不动时不吞这个键,页面照常滚动
ArrowRightfocus on 可展开且收起的行(dir=rtl 时改由 ArrowLeft 承担)就地展开当前行,焦点不动;不可展开、已展开或禁用的行上什么都不做且不吞键
ArrowLeftfocus on 可展开且已展开的行(dir=rtl 时改由 ArrowRight 承担)就地收起当前行,焦点不动;其余情形什么都不做且不吞键
Enter / Spacefocus on sort-trigger, 该列 sortable排序方向按 升序 → 降序 → 不排序 循环;按住 Shift 是追加到排序链而不是替换整条链
Enter / Spacefocus on select-all-trigger, selectionMode=multiple当前可选行全选中就整段清空,否则整段选上;三态由 aria-checked 报出(半选为 mixed)
Enter / Spacefocus on column-visibility-trigger藏起 / 放出这一列;设置区不是 roving 集合,一列一个 Tab 位,Tab 一路走下去即可逐列开关。只剩最后一列显示着时它转 aria-disabled,按了不动
Ctrl+A / Cmd+Afocus in table body, selectionMode=multiple与全选把手同义:当前可选行全选中就整段清空,否则整段选上(禁用行不算进基数)。单选与不可选的表格不吞这个键,交还浏览器的整页全选;按住不放的连发只算一次
ArrowLeft / ArrowRightfocus in column-resize-trigger,该列 resizable把这一列按 8px 收窄 / 加宽;往行尾侧推是加宽,rtl 下左右两键对调,语义恒是「加宽 / 收窄」
Shift+ArrowLeft / Shift+ArrowRightfocus in column-resize-trigger,该列 resizable按 40px 收窄 / 加宽,方向规则同上
ArrowLeft / ArrowRightfocus in column-drag-trigger,该列在可拖的那一段里把这一列往前 / 往后挪一位,按一下就是一次完整提交;往行首侧挪是往前,rtl 下左右两键对调,语义恒是「往前 / 往后」;已在段首 / 段末就不动,也不回绕
Home / Endfocus in column-drag-trigger,该列在可拖的那一段里把这一列挪到可拖那一段的段首 / 段末;rtl 下两键对调,语义恒是「段首 / 段末」;已经在那儿就不动
Alt+ArrowUp / Alt+ArrowDownfocus in table body,rowReorderable 且行拖拽没有被阻断的原因把焦点行往前 / 往后挪一位,按一下就是一次完整提交,不进拖动态;纵轴与文字方向无关,rtl 下两键不对调;已在首行 / 末行就不动,也不回绕;焦点锚点跟着搬走的那一行,连按几下能一路挪到位。裸方向键仍是导航、Space 仍是选中、左右键仍是展开收起
Alt+ArrowLeft / Alt+ArrowRightfocus in table body,rows 里有行声明了 parentId,rowReorderable 且行拖拽没有被阻断的原因把焦点行改一层缩进:往里是认上一个兄弟当爹,往外是变成父行的下一个兄弟;按一下就是一次完整提交,不进拖动态;横轴跟着文字方向翻,rtl 下两键对调,语义恒是「往里 / 往外」;没有上一个兄弟就缩不进去、已在根层就退不出来,两种情形都不动。rows 里一行都不带 parentId 时这两个键不归表格管,放行给页面

ARIA ​

以下属性由 connect 生成。

部件属性值
rootaria-busy'true' | undefined
rootaria-colcountcolumns.length || undefined
rootaria-labelledbycaption 部件的 id
rootaria-multiselectable'true' | 'false'
rootaria-rowcountHEADER_ROW_COUNT + visibleRows.length + (hasFooter ? …
rootrole'treegrid' | 'grid'
headerrole'rowgroup'
bodyrole'rowgroup'
footerrole'rowgroup'
rowaria-controlsdetail 部件的 id | undefined
rowaria-disabled'true' | 'false'
rowaria-expanded'true' | 'false' | undefined
rowaria-levelmetaIndex.get(row.value)?.level | undefined
rowaria-posinsetmetaIndex.get(row.value)?.posInSet | undefined
rowaria-rowindexdataRowIndex.get(row.value)
rowaria-selected'true' | 'false' | undefined
rowaria-setsizemetaIndex.get(row.value)?.setSize | undefined
rowrole'row'
column-headeraria-colindexcolumnIndex.get(column.value)
column-headeraria-sort'ascending' | 'descending' | 'none' | undefined
column-headerrole'columnheader'
cellaria-colindexcolumnIndex.get(cell.value)
cellaria-colspancell.colSpan | undefined
cellrole'gridcell'
toolbararia-labellabel.toolbar
column-listaria-labellabel.columnList
column-listrole'group'
column-visibility-triggeraria-checked'false' | 'true'
column-visibility-triggeraria-disabled'false' | 'true'
column-visibility-triggeraria-labellabel.columnVisibility(def?.label ?? column.value)
column-visibility-triggerrole'checkbox'
select-all-triggeraria-checked'true' | 'mixed' | 'false'
select-all-triggeraria-disabled'false' | 'true'
select-all-triggeraria-labellabel.selectAll
select-all-triggerrole'checkbox'
row-select-triggeraria-hidden'true'
sort-triggeraria-disabled'false' | 'true'
sort-triggeraria-labellabel.sort(def?.label ?? column.value)
sort-triggerrole'button'
column-resize-triggeraria-disabled'false' | 'true'
column-resize-triggeraria-labellabel.columnResize(def?.label ?? column.value)
column-resize-triggeraria-orientation'vertical'
column-resize-triggeraria-valuemaxdef?.maxWidth | undefined
column-resize-triggeraria-valuemindef?.minWidth | undefined
column-resize-triggeraria-valuenowcolumnNumericWidth(context.get('columnPreference').wi…
column-resize-triggerrole'separator'
column-drag-triggeraria-disabled'false' | 'true'
column-drag-triggeraria-labellabel.columnDrag(def?.label ?? column.value)
column-drag-triggeraria-roledescription'draggable column'
column-drag-triggerrole'button'
row-drag-triggeraria-hidden'true'
expand-triggeraria-hidden'true'
expanded-rowaria-level(metaIndex.get(row.value)?.level ?? 1) + 1 | undefined
expanded-rowaria-posinset1 | undefined
expanded-rowaria-rowindexdetailRowIndex.get(row.value)
expanded-rowaria-setsize1 | undefined
expanded-rowrole'row'
live-regionaria-atomic'true'
live-regionaria-live'polite'
live-regionrole'status'
header-rowaria-rowindex1
footer-rowaria-rowindexHEADER_ROW_COUNT + visibleRows.length + (hasFooter ? … | undefined
header-rowrole'row'
footer-rowrole'row'
  • 排序钮是 role=button,自占一个 Tab 位;它不包列名,可及名取 translations.sort(列名)(默认 Sort by <列名>),当前方向由所在列头的 aria-sort 报出,钮上不重复。
  • column-label 不带角色与状态:列头 role=columnheader 的可及名由它里面的文字算出,视觉上被省略号截断的列名读屏仍读全文。
  • 列宽把手与列拖拽把手同样各占一个 Tab 位,名字分别取 translations.columnResize 与 translations.columnDrag。
  • 行内的勾选框与展开箭头对读屏隐藏:选中与展开都由行自身的属性与方向键 / 空格承担。

样式参考 ​

皮肤 ​

@xihan-ui/styles/table.css 使用 [data-scope="table"][data-part="root"] 部件选择器,位于 xihan.components 与 xihan.motion 层。覆盖样式使用 xihan.overrides。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
rootdata-empty''(条件成立时才出现)
rootdata-fixed''(条件成立时才出现)
rootdata-loading''(条件成立时才出现)
rootdata-sizeprops.size
rootdata-split''(条件成立时才出现)
rootdata-striped''(条件成立时才出现)
rootdata-variantprops.variant
headerdata-fixed''(条件成立时才出现)
bodydata-empty''(条件成立时才出现)
rowdata-disabled''(条件成立时才出现)
rowdata-draggable''(条件成立时才出现)
rowdata-dragging''(条件成立时才出现)
rowdata-drop'before' | 'after' | 'inside'
rowdata-highlighted''(条件成立时才出现)
rowdata-pressed''(条件成立时才出现)
rowdata-section'body'
rowdata-selected''(条件成立时才出现)
rowdata-state'open' | 'closed' | undefined
rowdata-xh-collection-context'page'
rowdata-xh-collection-item''
rowdata-xh-collection-sizeprops.size
column-headerdata-dragging''(条件成立时才出现)
column-headerdata-drop'before' | 'after'
column-headerdata-frozenundefined
column-headerdata-sort'asc' | 'desc'
column-headerdata-sort-indextableSortIndexOf(sort, value) | undefined
column-headerdata-sortable''(条件成立时才出现)
celldata-disabled''(条件成立时才出现) | undefined
celldata-dragging''(条件成立时才出现)
celldata-drop'before' | 'after'
celldata-frozenundefined
celldata-selected''(条件成立时才出现) | undefined
toolbardata-sizeprops.size
column-listdata-sizeprops.size
column-visibility-triggerdata-disabled''(条件成立时才出现)
column-visibility-triggerdata-pressed''(条件成立时才出现)
column-visibility-triggerdata-state'unchecked' | 'checked'
column-visibility-triggerdata-xh-action-control''
column-visibility-triggerdata-xh-action-display'always'
column-visibility-triggerdata-xh-action-profile'icon'
column-visibility-triggerdata-xh-action-sizeprops.size
column-visibility-triggerdata-xh-action-variant'outline'
select-all-triggerdata-disabled''(条件成立时才出现)
select-all-triggerdata-pressed''(条件成立时才出现)
select-all-triggerdata-statetableSelectionState(selection, selectableIds)
select-all-triggerdata-xh-action-control''
select-all-triggerdata-xh-action-display'always'
select-all-triggerdata-xh-action-profile'icon'
select-all-triggerdata-xh-action-sizeprops.size
select-all-triggerdata-xh-action-variant'outline'
row-select-triggerdata-disabled''(条件成立时才出现)
row-select-triggerdata-highlighted''(条件成立时才出现)
row-select-triggerdata-pressed''(条件成立时才出现)
row-select-triggerdata-selected''(条件成立时才出现)
row-select-triggerdata-state'open' | 'closed' | undefined
row-select-triggerdata-xh-action-control''
row-select-triggerdata-xh-action-display'always'
row-select-triggerdata-xh-action-profile'icon'
row-select-triggerdata-xh-action-sizeprops.size
row-select-triggerdata-xh-action-variant'outline'
sort-triggerdata-disabled''(条件成立时才出现)
sort-triggerdata-pressed''(条件成立时才出现)
sort-triggerdata-sort'asc' | 'desc'
sort-triggerdata-sort-indextableSortIndexOf(sort, value) | undefined
sort-triggerdata-xh-action-control''
sort-triggerdata-xh-action-display'always'
sort-triggerdata-xh-action-profile'icon'
sort-triggerdata-xh-action-sizeprops.size
sort-triggerdata-xh-action-variant'ghost'
column-resize-triggerdata-disabled''(条件成立时才出现)
column-resize-triggerdata-resizing''(条件成立时才出现)
column-drag-triggerdata-disabled''(条件成立时才出现)
column-drag-triggerdata-dragging''(条件成立时才出现)
row-drag-triggerdata-disabled''(条件成立时才出现)
row-drag-triggerdata-dragging''(条件成立时才出现)
expand-triggerdata-disabled''(条件成立时才出现)
expand-triggerdata-highlighted''(条件成立时才出现)
expand-triggerdata-pressed''(条件成立时才出现)
expand-triggerdata-selected''(条件成立时才出现)
expand-triggerdata-state'open' | 'closed' | undefined
expand-triggerdata-xh-action-control''
expand-triggerdata-xh-action-display'always'
expand-triggerdata-xh-action-profile'icon'
expand-triggerdata-xh-action-sizeprops.size
expand-triggerdata-xh-action-variant'ghost'
expanded-rowdata-dragging''(条件成立时才出现)
expanded-rowdata-state'open' | 'closed'
load-more-triggerdata-loading''(条件成立时才出现)
load-more-triggerdata-pressed''(条件成立时才出现)
load-more-triggerdata-xh-action-control''
load-more-triggerdata-xh-action-display'always'
load-more-triggerdata-xh-action-profile'row'
load-more-triggerdata-xh-action-sizeprops.size
load-more-triggerdata-xh-action-variant'ghost'
header-rowdata-section'header'
footer-rowdata-section'footer'

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-table-bgrootbackgrounddefault
variant=outline
variant=subtle
--xh-bg-subtle
--xh-bg-surface
table 的 root 部件 background 覆盖槽。
--xh-table-borderfooter
header
root
border
border-block-end
border-block-start
default
variant=outline
--xh-border-defaulttable 的 footer、header、root 部件 border、border-block-end、border-block-start 覆盖槽。
--xh-table-caption-fgcaptioncolordefault--xh-fg-mutedtable 的 caption 部件 color 覆盖槽。
--xh-table-caption-font-sizecaptionfont-sizedefault--xh-text-label-sizetable 的 caption 部件 font-size 覆盖槽。
--xh-table-caption-font-weightcaptionfont-weightdefault--xh-text-label-weighttable 的 caption 部件 font-weight 覆盖槽。
--xh-table-caption-pxcaptionpadding-inlinedefault--xh-space-3table 的 caption 部件 padding-inline 覆盖槽。
--xh-table-caption-pycaptionpadding-blockdefault--xh-space-2table 的 caption 部件 padding-block 覆盖槽。
--xh-table-cell-gapcell
column-header
gapdefault--xh-control-gap-mdtable 的 cell、column-header 部件 gap 覆盖槽。
--xh-table-cell-min-wcell
column-header
min-inline-sizedefault3remtable 的 cell、column-header 部件 min-inline-size 覆盖槽。
--xh-table-cell-pxcell
column-header
padding-inlinedefault--xh-control-px-smtable 的 cell、column-header 部件 padding-inline 覆盖槽。
--xh-table-cell-pycell
column-header
padding-blockdefault--xh-_table-cell-pytable 的 cell、column-header 部件 padding-block 覆盖槽。
--xh-table-column-fgcolumn-headercolordefault--xh-fg-mutedtable 的 column-header 部件 color 覆盖槽。
--xh-table-column-font-weightcolumn-headerfont-weightdefault--xh-text-label-weighttable 的 column-header 部件 font-weight 覆盖槽。
--xh-table-column-list-fgcolumn-listcolordefault--xh-fg-defaulttable 的 column-list 部件 color 覆盖槽。
--xh-table-column-list-font-sizecolumn-listfont-sizedefault--xh-text-secondary-sizetable 的 column-list 部件 font-size 覆盖槽。
--xh-table-column-list-gapcolumn-listgapdefault--xh-_table-column-list-gaptable 的 column-list 部件 gap 覆盖槽。
--xh-table-detail-bgexpanded-rowbackgrounddefault--xh-bg-subtletable 的 expanded-row 部件 background 覆盖槽。
--xh-table-detail-pxcell
expanded-row
padding-inlinedefault--xh-space-4table 的 cell、expanded-row 部件 padding-inline 覆盖槽。
--xh-table-detail-pycell
expanded-row
padding-blockdefault--xh-space-3table 的 cell、expanded-row 部件 padding-block 覆盖槽。
--xh-table-drag-fgcolumn-drag-triggercolordefault--xh-fg-subtletable 的 column-drag-trigger 部件 color 覆盖槽。
--xh-table-drag-fg-activecolumn-drag-triggercolordisabled
dragging
hover
not([data-disabled])
--xh-fg-defaulttable 的 column-drag-trigger 部件 color 覆盖槽。
--xh-table-drag-fg-disabledcolumn-drag-triggercolordisabled--xh-fg-disabledtable 的 column-drag-trigger 部件 color 覆盖槽。
--xh-table-drag-grip-hcolumn-drag-triggerblock-sizeempty--xh-space-2table 的 column-drag-trigger 部件 block-size 覆盖槽。
--xh-table-drag-grip-wcolumn-drag-triggerinline-sizeempty--xh-space-1table 的 column-drag-trigger 部件 inline-size 覆盖槽。
--xh-table-drag-sizecolumn-drag-triggerblock-size
inline-size
default--xh-control-indicator-sizetable 的 column-drag-trigger 部件 block-size、inline-size 覆盖槽。
--xh-table-dragging-opacitycell
column-header
expanded-row
row
opacitydragging--xh-state-dragging-opacitytable 的 cell、column-header、expanded-row、row 部件 opacity 覆盖槽。
--xh-table-drop-fgcell
column-header
row
background
box-shadow
drop
drop=after
drop=before
drop=inside
frozen
is([data-drop='before'], [data-drop='after'])
not([data-frozen])
--xh-bg-brandtable 的 cell、column-header、row 部件 background、box-shadow 覆盖槽。
--xh-table-drop-inside-bgbody
root
row
backgrounddisabled
drop=inside
not([data-disabled])
--xh-bg-subtle-hover-opaquetable 的 body、root、row 部件 background 覆盖槽。
--xh-table-drop-linecell
column-header
row
block-size
box-shadow
inline-size
drop
drop=after
drop=before
drop=inside
frozen
is([data-drop='before'], [data-drop='after'])
not([data-frozen])
--xh-stroke-thicktable 的 cell、column-header、row 部件 block-size、box-shadow、inline-size 覆盖槽。
--xh-table-expand-fgexpand-triggercolordefault
disabled
focus-visible
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-fg-subtletable 的 expand-trigger 部件 color 覆盖槽。
--xh-table-fgrootcolordefault--xh-fg-defaulttable 的 root 部件 color 覆盖槽。
--xh-table-font-sizeroot
row
font-sizedefault--xh-_table-font-sizetable 的 root、row 部件 font-size 覆盖槽。
--xh-table-footer-bgfooterbackgrounddefault--xh-bg-subtletable 的 footer 部件 background 覆盖槽。
--xh-table-footer-font-weightfooterfont-weightdefault--xh-font-weight-mediumtable 的 footer 部件 font-weight 覆盖槽。
--xh-table-header-bgcolumn-header
header
backgrounddefault
frozen
--xh-bg-subtle-opaquetable 的 column-header、header 部件 background 覆盖槽。
--xh-table-icon-sizeroot--xh-icon-sizedefault
size=lg
size=sm
--xh-glyph-size-lg
--xh-glyph-size-md
--xh-glyph-size-sm
table 的 root 部件 --xh-icon-size 覆盖槽。
--xh-table-load-more-trigger-bg-hoverload-more-triggerbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hovertable 的 load-more-trigger 部件 background-color 覆盖槽。
--xh-table-load-more-trigger-fgload-more-triggercolordefault
disabled
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-fg-brand-strongtable 的 load-more-trigger 部件 color 覆盖槽。
--xh-table-load-more-trigger-font-sizeload-more-triggerfont-sizedefault--xh-_table-font-sizetable 的 load-more-trigger 部件 font-size 覆盖槽。
--xh-table-load-more-trigger-gapload-more-triggergapdefault--xh-space-2table 的 load-more-trigger 部件 gap 覆盖槽。
--xh-table-load-more-trigger-pxload-more-triggerpadding-inlinedefault--xh-space-4table 的 load-more-trigger 部件 padding-inline 覆盖槽。
--xh-table-load-more-trigger-pyload-more-triggerpadding-blockxh-action-profile=row--xh-space-3table 的 load-more-trigger 部件 padding-block 覆盖槽。
--xh-table-load-more-trigger-radiusload-more-triggerborder-radiusdefault--xh-shape-controltable 的 load-more-trigger 部件 border-radius 覆盖槽。
--xh-table-loading-durationloadinganimationdefault--xh-motion-loop-shimmertable 的 loading 部件 animation 覆盖槽。
--xh-table-max-hrootmax-block-sizedefault--xh-viewport-h-lgtable 的 root 部件 max-block-size 覆盖槽。
--xh-table-radiusrootborder-radiusvariant=outline
variant=subtle
--xh-shape-surfacetable 的 root 部件 border-radius 覆盖槽。
--xh-table-resize-fgcolumn-resize-triggerbackgrounddefault--xh-border-defaulttable 的 column-resize-trigger 部件 background 覆盖槽。
--xh-table-resize-fg-activecolumn-resize-triggerbackgroundhover
resizing
--xh-bg-brandtable 的 column-resize-trigger 部件 background 覆盖槽。
--xh-table-resize-linecolumn-resize-triggerinline-sizedefault--xh-stroke-thintable 的 column-resize-trigger 部件 inline-size 覆盖槽。
--xh-table-resize-line-lengthcolumn-resize-triggerblock-sizedefault60%table 的 column-resize-trigger 部件 block-size 覆盖槽。
--xh-table-resize-radiuscolumn-resize-triggerborder-radiusdefault--xh-shape-pilltable 的 column-resize-trigger 部件 border-radius 覆盖槽。
--xh-table-resize-widthcolumn-resize-triggerinline-sizedefault--xh-space-2table 的 column-resize-trigger 部件 inline-size 覆盖槽。
--xh-table-row-bgrowbackground-colordefault--xh-bg-surfacetable 的 row 部件 background-color 覆盖槽。
--xh-table-row-bg-hoverrowbackground-colordisabled
error
highlighted
hover
is(:focus-visible, [data-highlighted])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
--xh-bg-subtle-opaquetable 的 row 部件 background-color 覆盖槽。
--xh-table-row-bg-pressedrowbackground-colordisabled
error
is(:active, [data-pressed])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
--xh-bg-subtle-hover-opaquetable 的 row 部件 background-color 覆盖槽。
--xh-table-row-bg-selectedrowbackground-colordisabled
error
is([aria-selected='true'], [data-selected])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
selected
xh-collection-context=page
--xh-bg-brand-subtletable 的 row 部件 background-color 覆盖槽。
--xh-table-row-bg-stripedbody
root
row
background-colorstriped
where(:nth-of-type(even)
where([data-scope='table'][data-part='root'][data-striped] [data-scope='table'][data-part='body'])
--xh-bg-subtle-opaquetable 的 body、root、row 部件 background-color 覆盖槽。
--xh-table-row-borderbody
cell
column-header
expanded-row
footer
header
root
row
border-block-start
border-inline-end
is([data-part='header'], [data-part='body'], [data-part='footer'])
is([data-part='row'], [data-part='expanded-row'])
not(:last-child)
not([hidden])
split
--xh-border-subtletable 的 body、cell、column-header、expanded-row、footer、header、root、row 部件 border-block-start、border-inline-end 覆盖槽。
--xh-table-row-cursorrowcursordefault
disabled
error
highlighted
hover
is(:active, [data-pressed])
is(:focus-visible, [data-highlighted])
is([aria-selected='true'], [data-selected])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
selected
xh-collection-context=page
defaulttable 的 row 部件 cursor 覆盖槽。
--xh-table-row-drag-fgrow-drag-triggercolordefault--xh-fg-subtletable 的 row-drag-trigger 部件 color 覆盖槽。
--xh-table-row-drag-fg-activerow-drag-triggercolordisabled
dragging
hover
not([data-disabled])
--xh-fg-defaulttable 的 row-drag-trigger 部件 color 覆盖槽。
--xh-table-row-drag-fg-disabledrow-drag-triggercolordisabled--xh-fg-disabledtable 的 row-drag-trigger 部件 color 覆盖槽。
--xh-table-row-drag-grip-longrow-drag-triggerinline-sizeempty--xh-space-2table 的 row-drag-trigger 部件 inline-size 覆盖槽。
--xh-table-row-drag-grip-shortrow-drag-triggerblock-sizeempty--xh-space-1table 的 row-drag-trigger 部件 block-size 覆盖槽。
--xh-table-row-drag-sizerow-drag-triggerblock-size
inline-size
default--xh-control-indicator-sizetable 的 row-drag-trigger 部件 block-size、inline-size 覆盖槽。
--xh-table-row-fg-selectedrowcolordisabled
error
highlighted
hover
is(:active, [data-pressed])
is(:focus-visible, [data-highlighted])
is([aria-selected='true'], [data-selected])
not([aria-disabled='true'], [data-disabled], [aria-busy='true'], [data-error])
pressed
selected
xh-collection-context=page
--xh-fg-on-brand-subtletable 的 row 部件 color 覆盖槽。
--xh-table-sort-bg-hoversort-triggerbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hovertable 的 sort-trigger 部件 background-color 覆盖槽。
--xh-table-sort-bg-pressedsort-triggerbackground-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-bg-pressedtable 的 sort-trigger 部件 background-color 覆盖槽。
--xh-table-sort-fgsort-triggercolordefault
disabled
focus-visible
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-fg-subtletable 的 sort-trigger 部件 color 覆盖槽。
--xh-table-sort-fg-activesort-triggercolordisabled
focus-visible
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
sort
sort-index
--xh-fg-defaulttable 的 sort-trigger 部件 color 覆盖槽。
--xh-table-sort-sizesort-trigger--xh-icon-sizedefault--xh-_table-trigger-sizetable 的 sort-trigger 部件 --xh-icon-size 覆盖槽。
--xh-table-state-fgempty
loading
colordefault--xh-fg-mutedtable 的 empty、loading 部件 color 覆盖槽。
--xh-table-state-gapempty
loading
gapdefault--xh-space-2table 的 empty、loading 部件 gap 覆盖槽。
--xh-table-state-min-hempty
loading
min-block-sizedefault8remtable 的 empty、loading 部件 min-block-size 覆盖槽。
--xh-table-state-pxempty
loading
padding-inlinedefault--xh-space-4table 的 empty、loading 部件 padding-inline 覆盖槽。
--xh-table-state-pyempty
loading
padding-blockdefault--xh-space-6table 的 empty、loading 部件 padding-block 覆盖槽。
--xh-table-sticky-column-layercell
column-header
row
z-indexdrop=after
drop=before
drop=inside
frozen
is([data-drop='before'], [data-drop='after'])
1table 的 cell、column-header、row 部件 z-index 覆盖槽。
--xh-table-sticky-header-layerheaderz-indexfixed--xh-layer-stickytable 的 header 部件 z-index 覆盖槽。
--xh-table-sticky-insetcell
column-header
inset-inline-end
inset-inline-start
frozen=end
frozen=start
0table 的 cell、column-header 部件 inset-inline-end、inset-inline-start 覆盖槽。
--xh-table-toolbar-fgtoolbarcolordefault--xh-fg-defaulttable 的 toolbar 部件 color 覆盖槽。
--xh-table-toolbar-gaptoolbargapdefault--xh-_table-toolbar-gaptable 的 toolbar 部件 gap 覆盖槽。
--xh-table-toolbar-pytoolbarpadding-blockdefault--xh-space-2table 的 toolbar 部件 padding-block 覆盖槽。
--xh-table-trigger-bg-checkedcolumn-visibility-trigger
expand-trigger
row-select-trigger
select-all-trigger
sort-trigger
--xh-ink-surface
background-color
border
border-color
disabled
focus-visible
hover
is(:active, [data-pressed])
is([data-state='checked'], [data-state='indeterminate'])
loading
not([data-disabled])
not([data-loading])
pressed
selected
state=checked
state=indeterminate
xh-ink-surface
--xh-bg-brandtable 的 column-visibility-trigger、expand-trigger、row-select-trigger、select-all-trigger、sort-trigger 部件 --xh-ink-surface、background-color、border、border-color 覆盖槽。
--xh-table-trigger-bg-checked-pressedcolumn-visibility-trigger
expand-trigger
row-select-trigger
select-all-trigger
sort-trigger
background-colordisabled
is(:active, [data-pressed])
is([data-state='checked'], [data-state='indeterminate'])
loading
not([data-disabled])
not([data-loading])
pressed
selected
state=checked
state=indeterminate
--xh-bg-brand-activetable 的 column-visibility-trigger、expand-trigger、row-select-trigger、select-all-trigger、sort-trigger 部件 background-color 覆盖槽。
--xh-table-trigger-bg-pressedcolumn-visibility-trigger
expand-trigger
row-select-trigger
select-all-trigger
sort-trigger
background-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-bg-subtle-hovertable 的 column-visibility-trigger、expand-trigger、row-select-trigger、select-all-trigger、sort-trigger 部件 background-color 覆盖槽。
--xh-table-trigger-bordercolumn-visibility-trigger
expand-trigger
row-select-trigger
select-all-trigger
sort-trigger
border
border-color
default
disabled
focus-visible
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-border-controltable 的 column-visibility-trigger、expand-trigger、row-select-trigger、select-all-trigger、sort-trigger 部件 border、border-color 覆盖槽。
--xh-table-trigger-border-checkedcolumn-visibility-trigger
expand-trigger
row-select-trigger
select-all-trigger
sort-trigger
border
border-color
disabled
focus-visible
hover
is(:active, [data-pressed])
is([data-state='checked'], [data-state='indeterminate'])
loading
not([data-disabled])
not([data-loading])
pressed
selected
state=checked
state=indeterminate
--xh-table-trigger-bg-checkedtable 的 column-visibility-trigger、expand-trigger、row-select-trigger、select-all-trigger、sort-trigger 部件 border、border-color 覆盖槽。
--xh-table-trigger-fgcolumn-visibility-trigger
row-select-trigger
select-all-trigger
--xh-_ring-color
background-color
color
default
disabled
focus-visible
hover
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
state=indeterminate
--xh-fg-on-brandtable 的 column-visibility-trigger、row-select-trigger、select-all-trigger 部件 --xh-_ring-color、background-color、color 覆盖槽。
--xh-table-trigger-radiuscolumn-drag-trigger
column-visibility-trigger
expand-trigger
row-drag-trigger
row-select-trigger
select-all-trigger
sort-trigger
border-radiusdefault--xh-shape-control
--xh-shape-inset
table 的 column-drag-trigger、column-visibility-trigger、expand-trigger、row-drag-trigger、row-select-trigger、select-all-trigger、sort-trigger 部件 border-radius 覆盖槽。
--xh-table-trigger-sizecolumn-visibility-trigger
expand-trigger
row-select-trigger
select-all-trigger
sort-trigger
--xh-icon-size
block-size
inline-size
min-block-size
min-inline-size
default
xh-action-profile=icon
xh-action-profile=row
--xh-control-indicator-sizetable 的 column-visibility-trigger、expand-trigger、row-select-trigger、select-all-trigger、sort-trigger 部件 --xh-icon-size、block-size、inline-size、min-block-size、min-inline-size 覆盖槽。

动效 ​

动效角色:按压 · 状态 · 切换 · 循环(见动效规范)。

可覆盖的动效槽:--xh-table-loading-duration。

关键帧 xh-table-loading-pulse 随皮肤自带,不引用别处文件里的名字;background-color · rotate · scale 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

prefers-reduced-motion: reduce 下本组件另有降级规则。

响应式 ​

皮肤另按输入能力分档:pointer: coarse:同一份皮肤在触屏与带指针的设备上不一样,与视口宽度无关。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像;另有按 dir 分支的规则。

Released under The MIT License