Dragging rows
The row-draggable prop shows a grip icon to the left of the row. The move is reported by the row-reorder event — change the order in data yourself. A row can only be dropped between neighboring rows.
vue
<script setup lang="ts">
import type { NTable } from '@central-design-system/components';
import { CdsTable } from '@central-design-system/components';
import { ref } from 'vue';
type TRow = { key: string; name: string; category: string; price: string };
const columns: NTable.NColumn.TColumns<TRow> = [
{ title: 'Наименование', dataIndex: 'name', key: 'name' },
{ title: 'Категория', dataIndex: 'category', key: 'category' },
{ title: 'Цена', dataIndex: 'price', key: 'price', align: 'right' }
];
const data = ref<TRow[]>([
{ key: '1', name: 'iPhone 17 Pro Max', category: 'Смартфоны', price: '$1700' },
{ key: '2', name: 'MacBook Air M5', category: 'Ноутбуки', price: '$2000' },
{ key: '3', name: 'Apple Vision Pro', category: 'Гарнитуры', price: '$3500' },
{ key: '4', name: 'iPad Air', category: 'Планшеты', price: '$800' },
{ key: '5', name: 'AirPods Pro', category: 'Наушники', price: '$250' }
]);
const onRowReorder = (info: NTable.NDraggable.IRowReorderInfo<TRow>) => {
const next = [...data.value];
const dragIndex = next.findIndex((item) => item.key === info.dragKey);
if (dragIndex === -1) return;
const [moved] = next.splice(dragIndex, 1);
const dropIndex = next.findIndex((item) => item.key === info.dropKey);
next.splice(info.dropPosition === -1 ? dropIndex : dropIndex + 1, 0, moved);
data.value = next;
};
</script>
<template>
<CdsTable :columns="columns" :data="data" row-draggable :pagination="false" @row-reorder="onRowReorder" />
</template>Dragging nested rows
In a tree, a row is only reordered among the siblings of its own parent: it cannot be dropped onto another level — the cursor shows "not allowed" and no event arrives.
vue
<script setup lang="ts">
import type { NTable } from '@central-design-system/components';
import { CdsTable } from '@central-design-system/components';
import { ref } from 'vue';
type TRow = { key: number; name: string; price: number; children?: TRow[] };
const columns: NTable.NColumn.TColumns<TRow> = [
{ title: 'Название', dataIndex: 'name', key: 'name' },
{ title: 'Цена, $', dataIndex: 'price', key: 'price', align: 'right', width: '20%' }
];
const data = ref<TRow[]>([
{
key: 1,
name: 'Apple iPhone',
price: 3250,
children: [
{ key: 11, name: 'iPhone 14 Pro', price: 2000 },
{ key: 12, name: 'Power Bank', price: 50 },
{ key: 13, name: 'Headphones', price: 1200 }
]
},
{
key: 2,
name: 'Xiaomi Mi',
price: 200,
children: [
{ key: 21, name: 'Mi Band', price: 40 },
{ key: 22, name: 'Mi Buds', price: 60 }
]
}
]);
// Находит массив-родитель, содержащий строку с заданным ключом.
const findParentList = (list: TRow[], key: NTable.TKey): TRow[] | null => {
for (const item of list) {
if (item.key === key) return list;
if (item.children) {
const found = findParentList(item.children, key);
if (found) return found;
}
}
return null;
};
const onRowReorder = (info: NTable.NDraggable.IRowReorderInfo<TRow>) => {
const next = [...data.value];
// drag и drop гарантированно в одном родителе (reorder только между соседями).
const parentList = findParentList(next, info.dragKey);
if (!parentList) return;
const dragIndex = parentList.findIndex((item) => item.key === info.dragKey);
const [moved] = parentList.splice(dragIndex, 1);
const dropIndex = parentList.findIndex((item) => item.key === info.dropKey);
parentList.splice(info.dropPosition === -1 ? dropIndex : dropIndex + 1, 0, moved);
data.value = next;
};
</script>
<template>
<CdsTable
:columns="columns"
:data="data"
:default-expand-all-rows="true"
row-draggable
:pagination="false"
@row-reorder="onRowReorder"
/>
</template>Dragging columns
The column-draggable prop adds a grip icon to the header. The column-reorder event reports the new order — update the columns array.
vue
<script setup lang="ts">
import type { NTable } from '@central-design-system/components';
import { CdsTable } from '@central-design-system/components';
import { ref } from 'vue';
type TRow = { key: string; name: string; category: string; price: string; stock: string };
const columns = ref<NTable.NColumn.TColumns<TRow>>([
{ title: 'Наименование', dataIndex: 'name', key: 'name' },
{ title: 'Категория', dataIndex: 'category', key: 'category' },
{ title: 'Цена', dataIndex: 'price', key: 'price', align: 'right' },
{ title: 'Наличие', dataIndex: 'stock', key: 'stock' }
]);
const data: TRow[] = [
{ key: '1', name: 'iPhone 17 Pro Max', category: 'Смартфоны', price: '$1500', stock: 'В наличии' },
{ key: '2', name: 'MacBook Air M5', category: 'Ноутбуки', price: '$2000', stock: 'В наличии' },
{ key: '3', name: 'Apple Vision Pro', category: 'Гарнитуры', price: '$3500', stock: 'Нет в наличии' }
];
const onColumnReorder = (info: NTable.NDraggable.IColumnReorderInfo<TRow>) => {
const next = [...columns.value];
const dragIndex = next.indexOf(info.dragColumn);
if (dragIndex === -1) return;
const [moved] = next.splice(dragIndex, 1);
const dropIndex = next.indexOf(info.dropColumn);
next.splice(info.dropPosition === -1 ? dropIndex : dropIndex + 1, 0, moved);
columns.value = next;
};
</script>
<template>
<CdsTable :columns="columns" :data="data" column-draggable :pagination="false" @column-reorder="onColumnReorder" />
</template>Dragging columns with groups
A leaf column is reordered inside its own group, while a group header is dragged as a whole among neighboring groups.
vue
<script setup lang="ts">
import type { NTable } from '@central-design-system/components';
import { CdsTable } from '@central-design-system/components';
import { ref } from 'vue';
const columns = ref<NTable.NColumn.TColumns>([
{ title: 'Имя', dataIndex: 'name', key: 'name', width: 120 },
{
title: 'Контакты',
key: 'contacts',
children: [
{ title: 'Телефон', dataIndex: 'phone', key: 'phone', width: 160 },
{ title: 'Email', dataIndex: 'email', key: 'email', width: 200 }
]
},
{
title: 'Компания',
key: 'company',
children: [
{ title: 'Название', dataIndex: 'companyName', key: 'companyName', width: 160 },
{ title: 'Город', dataIndex: 'city', key: 'city', width: 140 }
]
}
]);
const data = [...Array(5)].map((_, i) => ({
key: i,
name: 'Иван',
phone: '+7 900 000-00-00',
email: 'ivan@b2b-center.ru',
companyName: 'B2B-Center',
city: 'Москва'
}));
// Находит массив-родитель (уровень группы), содержащий колонку по ссылке.
const findParentList = (
list: NTable.NColumn.TColumns,
column: NTable.NColumn.IColumn
): NTable.NColumn.TColumns | null => {
for (const col of list) {
if (col === column) return list;
const children = (col as NTable.NColumn.IColumnGroup).children;
if (children) {
const found = findParentList(children, column);
if (found) return found;
}
}
return null;
};
const onColumnReorder = (info: NTable.NDraggable.IColumnReorderInfo) => {
const next = [...columns.value];
const parentList = findParentList(next, info.dragColumn);
if (!parentList) return;
const dragIndex = parentList.indexOf(info.dragColumn);
const [moved] = parentList.splice(dragIndex, 1);
const dropIndex = parentList.indexOf(info.dropColumn);
parentList.splice(info.dropPosition === -1 ? dropIndex : dropIndex + 1, 0, moved);
columns.value = next;
};
</script>
<template>
<CdsTable
:columns="columns"
:data="data"
:scroll="{ x: 'max-content' }"
bordered
column-draggable
:pagination="false"
@column-reorder="onColumnReorder"
/>
</template>