Skip to content
On this page

Table

Display multiple data with similar format.

Basic

NameAgeAddress
Mike3210 Downing Street
John4210 Downing Street

Basic Usage
Basic table is just for data display.
<template>
  <v-table :dataSource="dataSource" :columns="columns"> </v-table>
</template>
<script setup lang="ts">
const dataSource = [
  {
    key: '1',
    name: 'Mike',
    age: 32,
    address: '10 Downing Street',
  },
  {
    key: '2',
    name: 'John',
    age: 42,
    address: '10 Downing Street',
  },
];
const columns = [
  {
    title: 'Name',
    dataIndex: 'name',
    key: 'name',
  },
  {
    title: 'Age',
    dataIndex: 'age',
    key: 'age',
  },
  {
    title: 'Address',
    dataIndex: 'address',
    key: 'address',
  },
];
</script>

Border

NameAgeAddress
Mike3210 Downing Street
John4210 Downing Street

Border
Use the bordered attribute to set the table display border.
<template>
  <v-table bordered :dataSource="dataSource" :columns="columns"> </v-table>
</template>
<script setup lang="ts">
const dataSource = [
  {
    key: '1',
    name: 'Mike',
    age: 32,
    address: '10 Downing Street',
  },
  {
    key: '2',
    name: 'John',
    age: 42,
    address: '10 Downing Street',
  },
];
const columns = [
  {
    title: 'Name',
    dataIndex: 'name',
    key: 'name',
  },
  {
    title: 'Age',
    dataIndex: 'age',
    key: 'age',
  },
  {
    title: 'Address',
    dataIndex: 'address',
    key: 'address',
  },
];
</script>

props.nameET
Header
NameAgeAddress
Mike3210 Downing Street
John4210 Downing Street

Customizing the header and footer
Customizing the header and footer of table by setting header and footer property.
<template>
  <v-table bordered :dataSource="dataSource" :columns="columns">
    <template #header>
      <div :style="{ display: 'flex', alignItems: 'center' }">
        <v-avatar name="Eobard Thawne" size="32px" />
        <span :style="{ marginLeft: '15px' }"> Header</span>
      </div>
    </template>
    <template #footer>
      <div :style="{ display: 'flex', alignItems: 'center' }">
        <v-avatar name="Eobard Thawne" size="32px" />
        <span :style="{ marginLeft: '15px' }"> Footer</span>
      </div>
    </template>
  </v-table>
</template>
<script setup lang="ts">
const dataSource = [
  {
    key: '1',
    name: 'Mike',
    age: 32,
    address: '10 Downing Street',
  },
  {
    key: '2',
    name: 'John',
    age: 42,
    address: '10 Downing Street',
  },
];
const columns = [
  {
    title: 'Name',
    dataIndex: 'name',
    key: 'name',
  },
  {
    title: 'Age',
    dataIndex: 'age',
    key: 'age',
  },
  {
    title: 'Address',
    dataIndex: 'address',
    key: 'address',
  },
];
</script>

Custom Cells

Custom Cell Presentation
props.name
Name
AgeAddressOperation
Edward King 0
32London, Park Lane no. 0
Edward King 1
32London, Park Lane no. 1

Custom Cells
Customize cells through slots.
<template>
  <v-button size="mini" type="primary" style="margin-bottom: 8px" @click="handleAdd">Add</v-button>
  <v-table bordered :dataSource="dataSource" :columns="columns">
    <template #header> Custom Cell Presentation </template>
    <template #headerCell="{ column }">
      <template v-if="column.key === 'name'">
        <span style="display: flex; align-items: center">
          <v-avatar src="https://avatars.dicebear.com/api/human/yard.svg?width=285&mood=happy" size="16px" />
          Name
        </span>
      </template>
    </template>
    <template #bodyCell="{ column, text, record }">
      <template v-if="column.dataIndex === 'name'">
        <div v-if="editableData[record.key]" class="editable-cell-wrapper">
          <v-input size="mini" v-model="editableData[record.key].name" />
          <v-button size="mini" class="editable-btn" @click="save(record.key)">save</v-button>
        </div>
        <div v-else class="editable-cell-wrapper">
          {{ text || ' ' }}
          <v-button size="mini" class="editable-btn" @click="edit(record.key)">edit</v-button>
        </div>
      </template>
      <template v-if="column.dataIndex === 'address'">
        <v-link style="color: red">{{ text }}</v-link>
      </template>
      <template v-if="column.dataIndex === 'operation'">
        <v-button size="mini" type="primary" @click="onDelete(record.key)">delete</v-button>
      </template>
    </template>
    <template #footer>
      <div :style="{ display: 'flex', alignItems: 'center' }">
        <v-avatar name="Eobard Thawne" size="32px" />
        <span :style="{ marginLeft: '15px' }"> Footer</span>
      </div>
    </template>
  </v-table>
</template>
<script setup lang="ts">
import { ref, computed, reactive } from 'vue';
import type { Ref, UnwrapRef } from 'vue';

interface DataItem {
  key: string;
  name: string;
  age: number;
  address: string;
}

const columns = [
  {
    title: 'Name',
    dataIndex: 'name',
    key: 'name',
  },
  {
    title: 'Age',
    dataIndex: 'age',
    key: 'age',
  },
  {
    title: 'Address',
    dataIndex: 'address',
    key: 'address',
  },
  {
    title: 'Operation',
    dataIndex: 'operation',
    key: 'operation',
  },
];
let dataSource: Ref<DataItem[]> = ref([
  {
    key: '0',
    name: 'Edward King 0',
    age: 32,
    address: 'London, Park Lane no. 0',
  },
  {
    key: '1',
    name: 'Edward King 1',
    age: 32,
    address: 'London, Park Lane no. 1',
  },
]);
const count = computed(() => dataSource.value.length + 1);
const editableData: UnwrapRef<Record<string, DataItem>> = reactive({});

const edit = (key: string) => {
  editableData[key] = JSON.parse(JSON.stringify(dataSource.value.find(item => key === item.key)));
};
const save = (key: string) => {
  Object.assign(dataSource.value.find(item => key === item.key) as DataItem, editableData[key]);
  delete editableData[key];
};
const handleAdd = () => {
  const newData = {
    key: `${count.value}`,
    name: `Edward King ${count.value}`,
    age: 32,
    address: `London, Park Lane no. ${count.value}`,
  };
  dataSource.value.push(newData);
};

const onDelete = (key: string) => {
  dataSource.value = dataSource.value.filter(item => item.key !== key);
};
</script>
<style scoped>
.editable-cell-wrapper {
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.editable-btn {
  margin-left: 5px;
}
</style>

Fixed Header

NameAgeAddress
Edward King 032London, Park Lane no. 0
Edward King 132London, Park Lane no. 1
Edward King 232London, Park Lane no. 2
Edward King 332London, Park Lane no. 3
Edward King 432London, Park Lane no. 4
Edward King 532London, Park Lane no. 5
Edward King 632London, Park Lane no. 6
Edward King 732London, Park Lane no. 7
Edward King 832London, Park Lane no. 8
Edward King 932London, Park Lane no. 9

Fixed Header
Display large amounts of data in scrollable view. Specify width of columns if header and cell do not align properly. If specified width is not working or have gutter between columns, please try to leave one column at least without width to fit fluid layout, or make sure no long word to break table layout.
<template>
  <v-table height="240px" bordered :dataSource="dataSource" :columns="columns"> </v-table>
</template>
<script setup lang="ts">
const dataSource = [...Array(10)].map((_, i) => ({
  key: i,
  name: `Edward King ${i}`,
  age: 32,
  address: `London, Park Lane no. ${i}`,
}));

const columns = [
  {
    title: 'Name',
    dataIndex: 'name',
    key: 'name',
    width: 150, // 🚨 Specify width of columns
  },
  {
    title: 'Age',
    dataIndex: 'age',
    key: 'age',
    width: 150, // 🚨 Specify width of columns
  },
  {
    title: 'Address',
    dataIndex: 'address',
    key: 'address',
  },
];
</script>

Fixed Columns

Full NameAgeColumn 1Column 2Column 3Column 4Column 5Column 6Column 7Column 8
Edward King 032London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0
Edward King 132London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1
Edward King 232London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2
Edward King 332London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3

Fixed Columns
To fix some columns and scroll inside other columns,The actual content width can be set through scrollWidth.
<template>
  <v-table :scrollWidth="2000" bordered :dataSource="dataSource" :columns="columnsFixed"> </v-table>
</template>
<script setup lang="ts">
interface ColumnProps {
  dataIndex?: string;
  title: string;
  key: string;
  width?: number | string;
  fixed?: boolean | string;
}
const dataSource = [...Array(4)].map((_, i) => ({
  key: i,
  name: `Edward King ${i}`,
  age: 32,
  address: `London, Park Lane no. ${i}`,
}));

const columnsFixed: Array<ColumnProps> = [
  { title: 'Full Name', width: 200, dataIndex: 'name', key: 'name', fixed: 'left' },
  { title: 'Age', width: 50, dataIndex: 'age', key: 'age' },
  { title: 'Column 1', dataIndex: 'address', key: '1' },
  { title: 'Column 2', dataIndex: 'address', key: '2' },
  { title: 'Column 3', dataIndex: 'address', key: '3' },
  { title: 'Column 4', dataIndex: 'address', key: '4' },
  { title: 'Column 5', dataIndex: 'address', key: '5' },
  { title: 'Column 6', dataIndex: 'address', key: '6' },
  { title: 'Column 7', dataIndex: 'address', key: '7' },
  { title: 'Column 8', dataIndex: 'address', key: '8', fixed: 'right' },
];
</script>

Fixed Header And Columns

Full NameAgeColumn 1Column 2Column 3Column 4Column 5Column 6Column 7Column 8
Edward King 032London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0London, Park Lane no. 0
Edward King 132London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1London, Park Lane no. 1
Edward King 232London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2London, Park Lane no. 2
Edward King 332London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3London, Park Lane no. 3
Edward King 432London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4London, Park Lane no. 4
Edward King 532London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5London, Park Lane no. 5
Edward King 632London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6London, Park Lane no. 6
Edward King 732London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7London, Park Lane no. 7
Edward King 832London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8London, Park Lane no. 8
Edward King 932London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9London, Park Lane no. 9

Fixed Head And Column
A Solution for displaying large amounts of data with long columns.
<template>
  <v-table height="240px" :scrollWidth="2000" bordered :dataSource="dataSource" :columns="columnsFixed" />
</template>
<script setup lang="ts">
interface ColumnProps {
  dataIndex?: string;
  title: string;
  key: string;
  width?: number | string;
  fixed?: boolean | string;
}
const dataSource = [...Array(10)].map((_, i) => ({
  key: i,
  name: `Edward King ${i}`,
  age: 32,
  address: `London, Park Lane no. ${i}`,
}));

const columnsFixed: Array<ColumnProps> = [
  { title: 'Full Name', width: 200, dataIndex: 'name', key: 'name', fixed: 'left' },
  { title: 'Age', width: 60, dataIndex: 'age', key: 'age' },
  { title: 'Column 1', dataIndex: 'address', key: '1' },
  { title: 'Column 2', dataIndex: 'address', key: '2' },
  { title: 'Column 3', dataIndex: 'address', key: '3' },
  { title: 'Column 4', dataIndex: 'address', key: '4' },
  { title: 'Column 5', dataIndex: 'address', key: '5' },
  { title: 'Column 6', dataIndex: 'address', key: '6' },
  { title: 'Column 7', dataIndex: 'address', key: '7' },
  { title: 'Column 8', dataIndex: 'address', key: '8', fixed: 'right' },
];
</script>