Columns
fixed Fixed Columns
column.fixed pins a column to either side of the table, keeping it visible during horizontal scrolling:
| 工号 | 姓名 | 岗位 | 地址 | 邮箱 | 薪资 |
|---|---|---|---|---|---|
P0001 | 李勇 | UI 设计师 | 北京市海淀区中关村大街 27 号中关村大厦 A 座 1502 | user1@movk.dev | ¥8,257 |
P0002 | 王超 | 运营专员 | 深圳市南山区科技园南区高新南九道 9 号深圳湾科技生态园 10 栋 B 座 2301 | user2@movk.dev | ¥8,514 |
P0003 | 陈娜 | 全栈工程师 | 广州市天河区珠江新城华夏路 16 号富力盈凯广场 38 楼 | user3@movk.dev | ¥8,771 |
P0004 | 刘丽 | 数据分析师 | 杭州市余杭区文一西路 969 号阿里巴巴西溪园区 6 号楼 318 | user4@movk.dev | ¥9,028 |
P0005 | 杨军 | 后端工程师 | 成都市高新区天府大道中段 1199 号天府软件园 D 区 5 号楼 1207 | user5@movk.dev | ¥9,285 |
P0006 | 黄涛 | 产品经理 | 南京市建邺区江东中路 222 号高科荣域大厦 19 层 | user6@movk.dev | ¥9,542 |
P0007 | 赵伟 | 前端工程师 | 武汉市洪山区光谷大道 70 号光谷国际企业中心 3 期 B 座 1808 | user7@movk.dev | ¥9,799 |
P0008 | 吴敏 | UI 设计师 | 上海市浦东新区张江高科技园区博云路 2 号 IBM 大厦 7 层 708 | user8@movk.dev | ¥10,056 |
<script setup lang="ts">
import type { DataTableColumn, DataTableDataColumn } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const data = makePeople(8)
const moneyCell: DataTableDataColumn<Person>['cell'] = ({ getValue }) => `¥${getValue<number>().toLocaleString()}`
const columns: DataTableColumn<Person>[] = [
{ accessorKey: 'id', header: '工号', fixed: 'left', size: 100 },
{ accessorKey: 'name', header: '姓名', fixed: 'left', size: 120 },
{ accessorKey: 'role', header: '岗位' },
{ accessorKey: 'address', header: '地址' },
{ accessorKey: 'email', header: '邮箱' },
{ accessorKey: 'salary', header: '薪资', fixed: 'right', align: 'right', cell: moneyCell }
]
</script>
<template>
<MDataTable :columns="columns" :data="data" :ui="{ root: 'max-w-2xl' }" />
</template>
children Grouped Headers
Define grouped columns (DataTableGroupColumn) using children to create multi-level headers:
| 员工信息 | 薪酬 | ||||
|---|---|---|---|---|---|
| 工号 | 姓名 | 部门 | 岗位 | 职级 | 薪资 |
P0001 | 李勇 | 产品 | UI 设计师 | P8 | ¥8,257 |
P0002 | 王超 | 市场 | 运营专员 | P7 | ¥8,514 |
P0003 | 陈娜 | 设计 | 全栈工程师 | P6 | ¥8,771 |
P0004 | 刘丽 | 运营 | 数据分析师 | P5 | ¥9,028 |
P0005 | 杨军 | 研发 | 后端工程师 | P8 | ¥9,285 |
P0006 | 黄涛 | 产品 | 产品经理 | P7 | ¥9,542 |
<script setup lang="ts">
import type { DataTableColumn, DataTableDataColumn } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const data = makePeople(6)
const moneyCell: DataTableDataColumn<Person>['cell'] = ({ getValue }) => `¥${getValue<number>().toLocaleString()}`
const columns: DataTableColumn<Person>[] = [
{ accessorKey: 'id', header: '工号' },
{
header: '员工信息',
children: [
{ accessorKey: 'name', header: '姓名' },
{ accessorKey: 'department', header: '部门' },
{ accessorKey: 'role', header: '岗位' }
]
},
{
header: '薪酬',
children: [
{ accessorKey: 'level', header: '职级' },
{ accessorKey: 'salary', header: '薪资', align: 'right', cell: moneyCell }
]
}
]
</script>
<template>
<MDataTable :columns="columns" :data="data" bordered />
</template>
sortable Column Sorting
The global sortable enables click-to-sort on all data column headers; a per-column sortable overrides the global setting in the opposite direction (e.g. sortable: false locks a column as non-sortable):
工号 | 姓名 | 职级 | 地址 | 薪资 |
|---|---|---|---|---|
P0001 | 李勇 | P8 | 北京市海淀区中关村大街 27 号中关村大厦 A 座 1502 | ¥8,257 |
P0002 | 王超 | P7 | 深圳市南山区科技园南区高新南九道 9 号深圳湾科技生态园 10 栋 B 座 2301 | ¥8,514 |
P0003 | 陈娜 | P6 | 广州市天河区珠江新城华夏路 16 号富力盈凯广场 38 楼 | ¥8,771 |
P0004 | 刘丽 | P5 | 杭州市余杭区文一西路 969 号阿里巴巴西溪园区 6 号楼 318 | ¥9,028 |
P0005 | 杨军 | P8 | 成都市高新区天府大道中段 1199 号天府软件园 D 区 5 号楼 1207 | ¥9,285 |
P0006 | 黄涛 | P7 | 南京市建邺区江东中路 222 号高科荣域大厦 19 层 | ¥9,542 |
P0007 | 赵伟 | P6 | 武汉市洪山区光谷大道 70 号光谷国际企业中心 3 期 B 座 1808 | ¥9,799 |
P0008 | 吴敏 | P5 | 上海市浦东新区张江高科技园区博云路 2 号 IBM 大厦 7 层 708 | ¥10,056 |
<script setup lang="ts">
import type { DataTableColumn, DataTableDataColumn } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const data = makePeople(8)
const moneyCell: DataTableDataColumn<Person>['cell'] = ({ getValue }) => `¥${getValue<number>().toLocaleString()}`
const columns: DataTableColumn<Person>[] = [
{ accessorKey: 'id', header: '工号', sortable: true },
{ accessorKey: 'name', header: '姓名' },
{ accessorKey: 'level', header: '职级', sortable: false },
{ accessorKey: 'address', header: '地址' },
{ accessorKey: 'salary', header: '薪资', align: 'right', cell: moneyCell }
]
</script>
<template>
<MDataTable :columns="columns" :data="data" />
</template>
pinable Column Pinning
The global pinable lets users click the pin icon on a header to cycle through left, right and none; a per-column pinable has higher priority and can force a fixed position:
工号 | 姓名 | 部门 | 岗位 | 薪资 |
|---|---|---|---|---|
P0001 | 李勇 | 产品 | UI 设计师 | ¥8,257 |
P0002 | 王超 | 市场 | 运营专员 | ¥8,514 |
P0003 | 陈娜 | 设计 | 全栈工程师 | ¥8,771 |
P0004 | 刘丽 | 运营 | 数据分析师 | ¥9,028 |
P0005 | 杨军 | 研发 | 后端工程师 | ¥9,285 |
P0006 | 黄涛 | 产品 | 产品经理 | ¥9,542 |
P0007 | 赵伟 | 市场 | 前端工程师 | ¥9,799 |
P0008 | 吴敏 | 设计 | UI 设计师 | ¥10,056 |
<script setup lang="ts">
import type { DataTableColumn, DataTableDataColumn } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const data = makePeople(8)
const moneyCell: DataTableDataColumn<Person>['cell'] = ({ getValue }) => `¥${getValue<number>().toLocaleString()}`
const columns: DataTableColumn<Person>[] = [
{ accessorKey: 'id', header: '工号', fixed: 'left', pinable: true },
{ accessorKey: 'name', header: '姓名' },
{ accessorKey: 'department', header: '部门', pinable: false },
{ accessorKey: 'role', header: '岗位' },
{ accessorKey: 'salary', header: '薪资', align: 'right', cell: moneyCell }
]
</script>
<template>
<MDataTable :columns="columns" :data="data" :ui="{ root: 'max-w-3xl' }" />
</template>
resizable Column Resize
The global resizable adds a drag handle to all data columns; resizable: false on a column locks its width. columnResizeMode controls whether reflow happens onChange (live during drag) or onEnd (after release):
工号 | 姓名 | 职级 | 地址 | 个人简介 |
|---|---|---|---|---|
P0001 | 李勇 | P8 | 北京市海淀区中关村大街 27 号中关村大厦 A 座 1502 | 负责自研低代码平台与 BFF 中间层,输出过若干内部脚手架与 CLI 工具,关注研发效率与可维护性。 |
P0002 | 王超 | P7 | 深圳市南山区科技园南区高新南九道 9 号深圳湾科技生态园 10 栋 B 座 2301 | 负责风控与反作弊算法工程化,搭建过实时特征平台与规则引擎,覆盖支付、营销、社交多场景。 |
P0003 | 陈娜 | P6 | 广州市天河区珠江新城华夏路 16 号富力盈凯广场 38 楼 | 长期投入大数据平台与离线计算调度,搭建过 PB 级数据仓库与数据治理体系,对数据质量与权限治理有较强经验。 |
P0004 | 刘丽 | P5 | 杭州市余杭区文一西路 969 号阿里巴巴西溪园区 6 号楼 318 | 深耕实时音视频与 WebRTC 互动场景,主导过千万级直播间的延迟优化与弱网降级方案。 |
P0005 | 杨军 | P8 | 成都市高新区天府大道中段 1199 号天府软件园 D 区 5 号楼 1207 | 聚焦移动端性能优化与跨端渲染框架,主导过启动耗时、内存与包体积的全链路治理。 |
P0006 | 黄涛 | P7 | 南京市建邺区江东中路 222 号高科荣域大厦 19 层 | 聚焦设计系统与组件库建设,推动跨产品视觉一致性,主导多次 Design Tokens 与暗色主题落地。 |
P0007 | 赵伟 | P6 | 武汉市洪山区光谷大道 70 号光谷国际企业中心 3 期 B 座 1808 | 在 To B SaaS 团队负责权限、计费与多租户体系,对 RBAC、ABAC 与审计合规有完整落地经验。 |
P0008 | 吴敏 | P5 | 上海市浦东新区张江高科技园区博云路 2 号 IBM 大厦 7 层 708 | 在跨境电商团队负责供应链与履约链路建设,主导过日均百万单的实时调度系统重构,关注稳定性与成本平衡。 |
<script setup lang="ts">
import type { DataTableColumn } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const data = makePeople(8)
const columns: DataTableColumn<Person>[] = [
{ accessorKey: 'id', header: '工号' },
{ accessorKey: 'name', header: '姓名', minSize: 80 },
{ accessorKey: 'level', header: '职级', resizable: false },
{ accessorKey: 'address', header: '地址', size: 120 },
{ accessorKey: 'bio', header: '个人简介', size: 150, resizable: true }
]
</script>
<template>
<MDataTable :columns="columns" :data="data" :ui="{ root: 'max-w-3xl' }" />
</template>
size / minSize / maxSize Column Width
size sets a fixed column width (a number or a preset xs–xl). When size is not set and only minSize / maxSize are provided, the column width adapts to content: minSize is the lower bound for auto-sizing and dragging; maxSize is the maximum draggable width. A column with size set is constrained in both directions by minSize / maxSize.
const columns: DataTableColumn<Person>[] = [
{ accessorKey: 'name', header: 'Name', minSize: 120 }, // auto, min 120
{ accessorKey: 'bio', header: 'Bio', maxSize: 240 }, // auto, drag max 240
{ accessorKey: 'id', header: 'ID', size: 'sm' } // fixed preset width 120
]
table-layout: auto and stretches to fill the container; auto-sized column content may exceed maxSize (auto layout ignores cell max-width). Therefore maxSize on an auto-sized column only constrains the drag upper limit. Use size to strictly fix a column width.fixed) require a known width to participate in sticky offset calculations, so they default to size. Only when a side has a single fixed column (the innermost fixed column closest to the scroll area) can that column auto-size to content — set minSize / maxSize to allow it to stretch (a typical example is the sole actions column on the right).Text Truncation and Tooltip
truncate controls pure truncation (true for single-line / number for multi-line / false to disable / a function for dynamic behavior); tooltip applies the same number of truncation lines and shows the full content in a float when it overflows. You do not need to configure both:
| 姓名 | 个人简介 | 角色 | 地址 |
|---|---|---|---|
李勇 | 负责自研低代码平台与 BFF 中间层,输出过若干内部脚手架与 CLI 工具,关注研发效率与可维护性。 | UI 设计师 | 北京市海淀区中关村大街 27 号中关村大厦 A 座 1502 |
王超 | 负责风控与反作弊算法工程化,搭建过实时特征平台与规则引擎,覆盖支付、营销、社交多场景。 | 运营专员 | 深圳市南山区科技园南区高新南九道 9 号深圳湾科技生态园 10 栋 B 座 2301 |
陈娜 | 长期投入大数据平台与离线计算调度,搭建过 PB 级数据仓库与数据治理体系,对数据质量与权限治理有较强经验。 | 全栈工程师 | 广州市天河区珠江新城华夏路 16 号富力盈凯广场 38 楼 |
刘丽 | 深耕实时音视频与 WebRTC 互动场景,主导过千万级直播间的延迟优化与弱网降级方案。 | 数据分析师 | 杭州市余杭区文一西路 969 号阿里巴巴西溪园区 6 号楼 318 |
杨军 | 聚焦移动端性能优化与跨端渲染框架,主导过启动耗时、内存与包体积的全链路治理。 | 后端工程师 | 成都市高新区天府大道中段 1199 号天府软件园 D 区 5 号楼 1207 |
黄涛 | 聚焦设计系统与组件库建设,推动跨产品视觉一致性,主导多次 Design Tokens 与暗色主题落地。 | 产品经理 | 南京市建邺区江东中路 222 号高科荣域大厦 19 层 |
赵伟 | 在 To B SaaS 团队负责权限、计费与多租户体系,对 RBAC、ABAC 与审计合规有完整落地经验。 | 前端工程师 | 武汉市洪山区光谷大道 70 号光谷国际企业中心 3 期 B 座 1808 |
吴敏 | 在跨境电商团队负责供应链与履约链路建设,主导过日均百万单的实时调度系统重构,关注稳定性与成本平衡。 | UI 设计师 | 上海市浦东新区张江高科技园区博云路 2 号 IBM 大厦 7 层 708 |
<script setup lang="ts">
import type { DataTableColumn } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const data = makePeople(8)
const columns: DataTableColumn<Person>[] = [
{ accessorKey: 'name', header: '姓名' },
{ accessorKey: 'bio', header: '个人简介', size: 240, tooltip: 1 },
{ accessorKey: 'role', header: '角色', size: 60 },
{ accessorKey: 'address', header: '地址', size: 200, truncate: true }
]
</script>
<template>
<MDataTable :columns="columns" :data="data" :ui="{ root: 'max-w-3xl' }" />
</template>
Column Visibility
column.visibility sets the default show/hide state; columnVisibilityKeys (allowlist) and columnVisibilityExcludeKeys (blocklist) are mutually exclusive — when both are provided the allowlist takes precedence:
| 工号 | 姓名 | 部门 | 岗位 | 职级 | 邮箱 | 薪资 |
|---|---|---|---|---|---|---|
P0001 | 李勇 | 产品 | UI 设计师 | P8 | user1@movk.dev | ¥8,257 |
P0002 | 王超 | 市场 | 运营专员 | P7 | user2@movk.dev | ¥8,514 |
P0003 | 陈娜 | 设计 | 全栈工程师 | P6 | user3@movk.dev | ¥8,771 |
P0004 | 刘丽 | 运营 | 数据分析师 | P5 | user4@movk.dev | ¥9,028 |
P0005 | 杨军 | 研发 | 后端工程师 | P8 | user5@movk.dev | ¥9,285 |
P0006 | 黄涛 | 产品 | 产品经理 | P7 | user6@movk.dev | ¥9,542 |
<script setup lang="ts">
import type { DataTableColumn, DataTableDataColumn } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const data = makePeople(6)
const moneyCell: DataTableDataColumn<Person>['cell'] = ({ getValue }) => `¥${getValue<number>().toLocaleString()}`
const columns: DataTableColumn<Person>[] = [
{ accessorKey: 'id', header: '工号' },
{ accessorKey: 'name', header: '姓名' },
{ accessorKey: 'department', header: '部门' },
{ accessorKey: 'role', header: '岗位' },
{ accessorKey: 'level', header: '职级' },
{ accessorKey: 'email', header: '邮箱' },
{ accessorKey: 'joinedAt', header: '入职日期', visibility: false },
{ accessorKey: 'salary', header: '薪资', align: 'right', cell: moneyCell }
]
</script>
<template>
<MDataTable :columns="columns" :data="data" />
</template>
Functional Configuration
sortable, pinable and resizable accept (col) => boolean; truncate and tooltip accept (ctx) => boolean | number. A single declaration replaces per-column booleans and can make dynamic decisions based on the field or cell context:
工号 | 姓名 | 部门 | 个人简介 | 地址 | 薪资 |
|---|---|---|---|---|---|
P0001 | 李勇 | 产品 | 北京市海淀区中关村大街 27 号中关村大厦 A 座 1502 | ¥8,257 | |
P0002 | 王超 | 市场 | 深圳市南山区科技园南区高新南九道 9 号深圳湾科技生态园 10 栋 B 座 2301 | ¥8,514 | |
P0003 | 陈娜 | 设计 | 广州市天河区珠江新城华夏路 16 号富力盈凯广场 38 楼 | ¥8,771 | |
P0004 | 刘丽 | 运营 | 杭州市余杭区文一西路 969 号阿里巴巴西溪园区 6 号楼 318 | ¥9,028 | |
P0005 | 杨军 | 研发 | 成都市高新区天府大道中段 1199 号天府软件园 D 区 5 号楼 1207 | ¥9,285 | |
P0006 | 黄涛 | 产品 | 南京市建邺区江东中路 222 号高科荣域大厦 19 层 | ¥9,542 | |
P0007 | 赵伟 | 市场 | 武汉市洪山区光谷大道 70 号光谷国际企业中心 3 期 B 座 1808 | ¥9,799 | |
P0008 | 吴敏 | 设计 | 上海市浦东新区张江高科技园区博云路 2 号 IBM 大厦 7 层 708 | ¥10,056 |
<script setup lang="ts">
import type { DataTableColumn, DataTableDataColumn, DataTableProps } from '@movk/nuxt'
import type { Person } from '~/composables/useTableMock'
const data = makePeople(8)
const moneyCell: DataTableDataColumn<Person>['cell'] = ({ getValue }) => `¥${getValue<number>().toLocaleString()}`
const columns: DataTableColumn<Person>[] = [
{ accessorKey: 'id', header: '工号' },
{ accessorKey: 'name', header: '姓名' },
{ accessorKey: 'department', header: '部门' },
{ accessorKey: 'bio', header: '个人简介' },
{ accessorKey: 'address', header: '地址', size: 200 },
{ accessorKey: 'salary', header: '薪资', align: 'right', cell: moneyCell }
]
const sortableFn: DataTableProps<Person>['sortable'] = col => col.accessorKey !== 'id'
const pinableFn: DataTableProps<Person>['pinable'] = col => !['bio', 'address'].includes(col.accessorKey)
const resizableFn: DataTableProps<Person>['resizable'] = col => col.accessorKey !== 'salary'
const truncateFn: DataTableDataColumn<Person>['truncate'] = ctx =>
ctx.column.id === 'bio' ? (ctx.row.original.bio.length > 45 ? 3 : 2) : true
const tooltipFn: DataTableDataColumn<Person>['tooltip'] = ctx => ctx.column.id === 'address'
</script>
<template>
<MDataTable
:columns="columns"
:data="data"
:sortable="sortableFn"
:pinable="pinableFn"
:resizable="resizableFn"
:truncate="truncateFn"
:tooltip="tooltipFn"
/>
</template>
Appearance
Component style overrides, pagination style overrides, stripe and borders, visual density, fit-content width, empty-cell placeholders and sticky header.
Special Columns
Configuration for selection, index, row-pinning and actions columns — including tree selection strategies, dynamic button props and confirmation dialogs.