Skip to content

Crud Table

z-crud component table functionality introduction. Table functionality usage is basically equivalent to z-table.

Table Usage

Encapsulated on z-table, table attributes can be passed directly.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  time: string
}

const columns = ref([
  {
    type: 'selection',
    reserveSelection: true,
  },
  {
    label: 'Name',
    prop: 'name',
  },
  {
    prop: 'gender',
    label: 'Gender',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
])
const request = ref({
  searchApi: getTableData,
})
const tableData = ref([])
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 0,
})
const loading = ref(false)
const selectionData = ref<RowData[]>([])

function getTableData(params: any) {
  console.log(params, 'getTableData params')
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          time: '2020-01-01',
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          time: '2012-01-01',
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          time: '2018-01-01',
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          time: '2028-01-01',
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 2,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}
</script>

<template>
  <z-crud
    v-model:data="tableData"
    v-model:pagination="pagination"
    v-model:loading="loading"
    v-model:selectionData="selectionData"
    :columns="columns"
    :request="request"
    :action="false"
    row-key="id"
    stripe
  />
</template>

Table Title

Configure title attribute to generate table title, supports string and function types, can also use tableTitle slot for customization.

<script lang="ts" setup>
import { ref } from 'vue'

const columns = ref([
  {
    label: 'Name',
    prop: 'name',
  },
  {
    prop: 'gender',
    label: 'Gender',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
])
const request = ref({
  searchApi: getTableData,
})
const tableData = ref([])
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 0,
})
const loading = ref(false)

function getTableData() {
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          time: '2020-01-01',
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          time: '2012-01-01',
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          time: '2018-01-01',
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          time: '2028-01-01',
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 2,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}
</script>

<template>
  <z-crud
    v-model:data="tableData"
    v-model:pagination="pagination"
    v-model:loading="loading"
    :columns="columns"
    :request="request"
    :action="false"
    title="Table Title"
  />
</template>

Operation Items

Operation items are appended to the end of columns by default, with table header as Operation, having three operations: View, Edit, Delete.

For specific configuration of operations, please refer to Create/Edit Configuration, View Configuration, Delete Configuration documentation.

Supports dynamic control of specific operation visibility.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { TableFormConfig } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  time: string
}

interface GetTableDataRes { data: { page: number, pageSize: number, list: RowData[], total: number } }

const columns = ref([
  {
    label: 'Name',
    prop: 'name',
  },
  {
    prop: 'gender',
    label: 'Gender',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
])
const request = ref({
  searchApi: getTableData,
})
const tableData = ref<RowData[]>([])
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 0,
})
const loading = ref(false)
const detailConfig = ref<TableFormConfig | boolean>(true)
const deleteConfig = ref<TableFormConfig | boolean>(true)
const editConfig = ref<TableFormConfig | boolean>(true)

function getTableData(params: any): Promise<GetTableDataRes> {
  console.log(params, 'getTableData params')
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          time: '2020-01-01',
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          time: '2012-01-01',
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          time: '2018-01-01',
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          time: '2028-01-01',
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 2,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}

function handleChangeViewVisible() {
  detailConfig.value = !detailConfig.value
}

function handleChangeDeleteVisible() {
  deleteConfig.value = !deleteConfig.value
}

function handleChangeEditVisible() {
  editConfig.value = !editConfig.value
}
</script>

<template>
  <z-crud
    v-model:data="tableData"
    v-model:pagination="pagination"
    v-model:loading="loading"
    :columns="columns"
    :request="request"
    :detail="detailConfig"
    :edit="editConfig"
    :delete="deleteConfig"
  >
    <template #toolBarLeft>
      <el-button type="primary" size="small" @click="handleChangeViewVisible">
        Toggle view button
      </el-button>
      <el-button type="primary" size="small" @click="handleChangeDeleteVisible">
        Toggle delete button
      </el-button>
      <el-button type="primary" size="small" @click="handleChangeEditVisible">
        Toggle edit button
      </el-button>
    </template>
  </z-crud>
</template>

Custom Operation Items

Configure action to false to disable default operation items and customize table operations.

Operation buttons also support dynamic attributes, such as: disabled, etc. Pass a method with current row related data as parameter.

<!-- eslint-disable unused-imports/no-unused-vars -->
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { TableColumnScopeData } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  time: string
}

const columns = ref([
  {
    label: 'Name',
    prop: 'name',
  },
  {
    prop: 'gender',
    label: 'Gender',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
  {
    type: 'button',
    label: 'Actions',
    buttons: [
      {
        label: 'View',
        link: true,
        type: 'primary',
        disabled: ({ row, column, $index }: TableColumnScopeData<RowData>) => row.name === 'Steven',
        onClick: ({ row }: TableColumnScopeData<RowData>) => console.log(row, 'row'),
      },
      {
        label: 'Delete',
        link: true,
        type: 'danger',
        disabled: ({ row, column, $index }: TableColumnScopeData<RowData>) => row.age === 18,
        onClick: ({ row }: TableColumnScopeData<RowData>) => console.log(row, 'row'),
      },
    ],
  },
])
const request = ref({
  searchApi: getTableData,
})
const tableData = ref([])
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 0,
})
const loading = ref(false)

function getTableData(params: any) {
  console.log(params, 'getTableData params')
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          time: '2020-01-01',
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          time: '2012-01-01',
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          time: '2018-01-01',
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          time: '2028-01-01',
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 2,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}
</script>

<template>
  <z-crud
    v-model:data="tableData"
    v-model:pagination="pagination"
    v-model:loading="loading"
    :columns="columns"
    :request="request"
    :action="false"
  />
</template>

Operation Dropdown

For other specific configurations, refer to z-table component

Configure type as dropdown in buttons array, configure dropdown options in children

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'
import type { TableColumnScopeData } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  time: string
}

const columns = ref([
  {
    label: 'Name',
    prop: 'name',
  },
  {
    prop: 'gender',
    label: 'Gender',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
  {
    type: 'button',
    label: 'Actions',
    width: '200px',
    buttons: [
      {
        type: 'primary',
        link: true,
        label: 'Edit',
        onClick: ({ row }: TableColumnScopeData<RowData>) => {
          console.log(row, 'edit')
        },
      },
      {
        type: 'danger',
        link: true,
        label: 'Delete',
        onClick: ({ row }: TableColumnScopeData<RowData>) => {
          console.log(row, 'delete')
        },
      },
      {
        type: 'dropdown',
        reference: 'More',
        children: [
          {
            type: 'primary',
            link: true,
            label: 'Copy',
            onClick: ({ row }: TableColumnScopeData<RowData>) => {
              console.log(row, 'copy')
            },
          },
          {
            type: 'danger',
            link: true,
            label: 'Operate',
            onClick: ({ row }: TableColumnScopeData<RowData>) => {
              console.log(row, 'operate')
            },
          },
        ],
      },
    ],
  },
])
const request = ref({
  searchApi: getTableData,
})
const tableData = ref([])
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 0,
})
const loading = ref(false)

function getTableData(params: any) {
  console.log(params, 'getTableData params')
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          time: '2020-01-01',
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          time: '2012-01-01',
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          time: '2018-01-01',
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          time: '2028-01-01',
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 2,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}
</script>

<template>
  <z-crud
    v-model:data="tableData"
    v-model:pagination="pagination"
    v-model:loading="loading"
    :columns="columns"
    :request="request"
    :action="false"
  />
</template>

Pagination

Configure pagination, supports two-way binding to implement pagination effect.

When pageSize is 0, pagination is false or pagination is not passed, pagination will not be displayed.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'

interface RowData {
  name: string
  gender: string
  age: number
  time: string
}

interface GetTableDataRes { result: { page: number, pageSize: number, list: RowData[], total: number } }

const loading = ref(false)
const tableData = ref<RowData[]>([])
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 0,
  layout: 'total, sizes, prev, pager, next, jumper',
})

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
  },
  {
    prop: 'gender',
    label: 'Gender',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
])

function mockApi(params: any): Promise<GetTableDataRes> {
  console.log(params, 'params')
  return new Promise((resolve) => {
    setTimeout(() => {
      const dataFirstPage = [
        {
          name: 'Steven',
          gender: 'male',
          age: 22,
          time: '2020-01-01',
        },
        {
          name: 'Helen',
          gender: 'male',
          age: 12,
          time: '2012-01-01',
        },
      ]
      const dataSecondPage = [
        {
          name: 'Nancy',
          gender: 'female',
          age: 18,
          time: '2018-01-01',
        },
        {
          name: 'Jack',
          gender: 'male',
          age: 28,
          time: '2028-01-01',
        },
      ]
      resolve({
        result: {
          page: 1,
          pageSize: 10,
          total: 4,
          list: pagination.value.page === 1 ? dataFirstPage : dataSecondPage,
        },
      })
    }, 100)
  })
}

async function getTableData() {
  loading.value = true
  try {
    const res = await mockApi({ ...pagination.value })
    tableData.value = res.result.list
    pagination.value.total = res.result.total
  }
  catch (error) {
    console.log(error)
  }
  loading.value = false
}

getTableData()
</script>

<template>
  <z-crud
    v-model:pagination="pagination"
    v-model:data="tableData"
    v-model:loading="loading"
    :columns="columns"
    :action="false"
    @refresh="getTableData"
  />
</template>

Frontend Pagination

Configure pagination type as front to enable frontend pagination functionality.

[]
<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'

interface RowData {
  name: string
  gender: string
  age: number
  time: string
}

interface GetTableDataRes { result: { page: number, pageSize: number, list: RowData[], total: number } }

const loading = ref(false)
const tableData = ref<RowData[]>([])
const totalData = ref<RowData[]>([])
const pagination = ref({
  type: 'front',
  page: 1,
  pageSize: 2,
  total: 0,
  layout: 'total, sizes, prev, pager, next, jumper',
})

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
  },
  {
    prop: 'gender',
    label: 'Gender',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
])

function mockApi(params: any): Promise<GetTableDataRes> {
  console.log(params, 'params')
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          name: 'Steven',
          gender: 'male',
          age: 22,
          time: '2020-01-01',
        },
        {
          name: 'Helen',
          gender: 'male',
          age: 12,
          time: '2012-01-01',
        },
        {
          name: 'Nancy',
          gender: 'female',
          age: 18,
          time: '2018-01-01',
        },
        {
          name: 'Jack',
          gender: 'male',
          age: 28,
          time: '2028-01-01',
        },
      ]

      resolve({
        result: {
          page: 1,
          pageSize: 10,
          total: 4,
          list: data,
        },
      })
    }, 100)
  })
}

async function getTableData() {
  loading.value = true
  try {
    const res = await mockApi({ ...pagination.value })
    totalData.value = res.result.list
    pagination.value.total = res.result.total
  }
  catch (error) {
    console.log(error)
  }
  loading.value = false
}

getTableData()
</script>

<template>
  {{ tableData }}
  <z-crud
    v-model:pagination="pagination"
    v-model:data="tableData"
    v-model:loading="loading"
    :total-data="totalData"
    :columns="columns"
    :action="false"
    @refresh="getTableData"
  />
</template>

Hide Columns

Configure hide field in column, supports function or boolean value.

<script lang="ts" setup>
import { ref } from 'vue'

const isHide = ref(false)
const tableData = ref([
  {
    name: 'Steven',
    gender: 'male',
    age: 22,
    time: '2020-01-01',
  },
  {
    name: 'Helen',
    gender: 'male',
    age: 12,
    time: '2012-01-01',
  },
  {
    name: 'Nancy',
    gender: 'female',
    age: 18,
    time: '2018-01-01',
  },
  {
    name: 'Jack',
    gender: 'male',
    age: 28,
    time: '2028-01-01',
  },
])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    hide: () => isHide.value,
  },
  {
    prop: 'gender',
    label: 'Gender',
    hide: true,
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
])

function changeVisible() {
  isHide.value = !isHide.value
}
</script>

<template>
  <el-button @click="changeVisible">
    Toggle column visibility
  </el-button>
  <z-crud
    v-model:data="tableData"
    :columns="columns"
    :action="false"
  />
</template>

Custom Column

Configure slot or render in column items to customize column content.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { h, ref } from 'vue'
import type { TableColumnScopeData } from 'ideaz-element'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  time: string
}

const columns = ref([
  {
    label: 'Name',
    slot: 'name',
    form: {
      component: 'input',
      label: 'Name',
      field: 'name',
    },
  },
  {
    slot: 'gender',
    label: 'Gender',
    form: {
      component: 'select',
      label: 'Gender',
      field: 'gender',
    },
  },
  {
    render: ({ row }: TableColumnScopeData<RowData>) => h('span', row.age),
    label: 'Age',
    form: {
      component: 'input',
      label: 'Age',
      field: 'age',
    },
  },
  {
    prop: 'time',
    label: 'Date',
  },
])
const request = ref({
  searchApi: getTableData,
  deleteApi: commonApi,
  submitApi: commonApi,
})
const tableData = ref([])
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 0,
})
const loading = ref(false)
const formData = ref({})

const options = {
  gender: [{ label: 'male', value: 'male' }, { label: 'female', value: 'female' }],
}

function getTableData(params: any) {
  console.log(params, 'getTableData params')
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          time: '2020-01-01',
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          time: '2012-01-01',
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          time: '2018-01-01',
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          time: '2028-01-01',
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 2,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}

function commonApi(params: any) {
  console.log(params, 'commonApi params')
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({
        msg: 'success',
        code: 200,
      })
    }, 100)
  })
}
</script>

<template>
  <z-crud
    v-model:formData="formData"
    v-model:data="tableData"
    v-model:pagination="pagination"
    v-model:loading="loading"
    :options="options"
    :columns="columns"
    :request="request"
  >
    <template #name>
      sdf
    </template>
    <template #gender>
      asdf
    </template>
  </z-crud>
</template>

Column Tooltip

Configure tooltip in column to implement table header tooltip functionality, supports function and string.

<script lang="ts" setup>
import { h, ref } from 'vue'

const tableData = ref([
  {
    name: 'Steven',
    gender: 'male',
    age: 22,
    time: '2020-01-01',
  },
  {
    name: 'Helen',
    gender: 'male',
    age: 12,
    time: '2012-01-01',
  },
  {
    name: 'Nancy',
    gender: 'female',
    age: 18,
    time: '2018-01-01',
  },
  {
    name: 'Jack',
    gender: 'male',
    age: 28,
    time: '2028-01-01',
  },
])

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    tooltip: () => h('span', 'Name tooltip'),
  },
  {
    prop: 'gender',
    label: 'Gender',
    tooltip: 'Gender tooltip',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
])
</script>

<template>
  <z-crud
    v-model:data="tableData"
    :columns="columns"
    :action="false"
  />
</template>

Column Types

Configure type in column to implement table column types, supports expand, radio, selection, input, select.

TIP

When type is sort, type is radio or cross-page selection checkbox is needed, it needs to be used with rowKey (default id).

<script lang="ts" setup>
import { ref } from 'vue'

const tableData = ref([
  {
    id: 1,
    name: 'Steven',
    gender: '1',
    age: 22,
    time: '2020-01-01',
  },
  {
    id: 2,
    name: 'Helen',
    gender: '1',
    age: 12,
    time: '2012-01-01',
  },
  {
    id: 3,
    name: 'Nancy',
    gender: '2',
    age: 18,
    time: '2018-01-01',
  },
  {
    id: 4,
    name: 'Jack',
    gender: '1',
    age: 28,
    time: '2028-01-01',
  },
])

const columns = ref([
  {
    type: 'sort',
  },
  {
    type: 'expand',
  },
  {
    type: 'index',
  },
  {
    type: 'radio',
  },
  {
    type: 'selection',
    reserveSelection: true,
  },
  {
    component: 'input',
    prop: 'name',
    label: 'Name',
  },
  {
    component: 'select',
    prop: 'gender',
    label: 'Gender',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
])

const options = {
  gender: [
    { label: 'Male', value: '1' },
    { label: 'Female', value: '2' },
  ],
}
</script>

<template>
  <z-crud
    v-model:data="tableData"
    :columns="columns"
    :options="options"
    :action="false"
    row-key="id"
  >
    <template #expand>
      <span>Expanded content</span>
    </template>
  </z-crud>
</template>

Custom Table Header

Configure label in column as string with slot or Slot or configure as render function to implement custom column header.

<script lang="ts" setup>
import { h, ref } from 'vue'

const tableData = ref([
  {
    name: 'Steven',
    gender: 'male',
    age: 22,
    time: '2020-01-01',
  },
  {
    name: 'Helen',
    gender: 'male',
    age: 12,
    time: '2012-01-01',
  },
  {
    name: 'Nancy',
    gender: 'female',
    age: 18,
    time: '2018-01-01',
  },
  {
    name: 'Jack',
    gender: 'male',
    age: 28,
    time: '2028-01-01',
  },
])

const columns = ref([
  {
    prop: 'name',
    label: () => h('span', 'Custom header'),
  },
  {
    prop: 'gender',
    label: 'genderHeaderSlot',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
])
</script>

<template>
  <z-crud
    v-model:data="tableData"
    :columns="columns"
    :action="false"
  >
    <template #genderHeaderSlot="scope">
      <span>Custom gender header {{ scope.$index }}</span>
    </template>
  </z-crud>
</template>

Editable Table

For detailed documentation, please refer to z-table editable table content.

Set editable to true to enable table edit mode. This field supports boolean or object type, editable table type defaults to single.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'

const tableData = ref([
  {
    name: 'Steven',
    gender: '1',
    age: 22,
    time: '2020-01-01',
  },
  {
    name: 'Helen',
    gender: '1',
    age: 12,
    time: '2012-01-01',
  },
  {
    name: 'Nancy',
    gender: '2',
    age: 18,
    time: '2018-01-01',
  },
  {
    name: 'Jack',
    gender: '1',
    age: 28,
    time: '2028-01-01',
  },
])

const columns = ref([
  {
    component: 'input',
    prop: 'name',
    label: 'Name',
  },
  {
    component: 'select',
    prop: 'gender',
    label: 'Gender',
  },
  {
    component: 'input',
    prop: 'age',
    label: 'Age',
  },
  {
    component: 'el-date-picker',
    prop: 'time',
    label: 'Date',
    fieldProps: {
      valueFormat: 'YYYY-MM-DD',
    },
  },
])

const options = {
  gender: [
    { label: 'Male', value: '1' },
    { label: 'Female', value: '2' },
  ],
}

function handleClick() {
  console.log(tableData.value, 'handleClick')
}
</script>

<template>
  <el-button @click="handleClick">
    click
  </el-button>
  <z-crud
    v-model:data="tableData"
    :columns="columns"
    :options="options"
    :editable="true"
    :action="false"
  />
</template>

Sticky

Implement sticky functionality by configuring sticky attribute's top, parent (DOM element where scroll bar appears) and zIndex. top defaults to 50px, zIndex defaults to 100.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  time: string
}

const searchFormData = ref({
  name: '',
})

const columns = ref([
  {
    type: 'selection',
    reserveSelection: true,
  },
  {
    label: 'Name',
    prop: 'name',
    search: {
      component: 'el-input',
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
])
const request = ref({
  searchApi: getTableData,
})
const tableData = ref([])
const pagination = ref({
  page: 1,
  pageSize: 2,
  total: 0,
})
const loading = ref(false)
const selectionData = ref<RowData[]>([])

function getTableData(params: any) {
  console.log(params, 'getTableData params')
  return new Promise((resolve) => {
    setTimeout(() => {
      const data = [
        {
          id: 1,
          name: 'Steven',
          gender: 'male',
          age: 22,
          time: '2020-01-01',
        },
        {
          id: 2,
          name: 'Helen',
          gender: 'male',
          age: 12,
          time: '2012-01-01',
        },
        {
          id: 3,
          name: 'Nancy',
          gender: 'female',
          age: 18,
          time: '2018-01-01',
        },
        {
          id: 4,
          name: 'Jack',
          gender: 'male',
          age: 28,
          time: '2028-01-01',
        },
      ]

      resolve({
        data: {
          page: 1,
          pageSize: 2,
          total: 4,
          list: data.slice((pagination.value.page - 1) * pagination.value.pageSize, pagination.value.page * pagination.value.pageSize),
        },
      })
    }, 100)
  })
}
</script>

<template>
  <z-crud
    v-model:data="tableData"
    v-model:pagination="pagination"
    v-model:loading="loading"
    v-model:selectionData="selectionData"
    v-model:formData="searchFormData"
    :columns="columns"
    :request="request"
    :action="false"
    :sticky="{ parent: 'document' }"
    row-key="id"
    stripe
  />
</template>

Watermark

Configure watermark, supports string and object types. For object type configurable attributes, refer to el-watermark configuration.

<script lang="ts" setup>
import { ref } from 'vue'

const tableData = ref([
  {
    name: 'Steven',
    gender: '1',
    age: 22,
    time: '2020-01-01',
  },
  {
    name: 'Helen',
    gender: '1',
    age: 12,
    time: '2012-01-01',
  },
  {
    name: 'Nancy',
    gender: '2',
    age: 18,
    time: '2018-01-01',
  },
  {
    name: 'Jack',
    gender: '1',
    age: 28,
    time: '2028-01-01',
  },
])
const formData = ref({})

const columns = ref([
  {
    prop: 'name',
    label: 'Name',
    form: {
      component: 'input',
      field: 'name',
    },
  },
  {
    prop: 'gender',
    label: 'Gender',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
])

const options = {
  gender: [
    { label: 'Male', value: '1' },
    { label: 'Female', value: '2' },
  ],
}
</script>

<template>
  <z-crud
    v-model:data="tableData"
    v-model:formData="formData"
    :columns="columns"
    :options="options"
    :action="false"
    watermark="watermark"
  />
</template>

Table Methods

z-crud table methods can be used according to el-table.

<!-- eslint-disable no-console -->
<script lang="ts" setup>
import { ref } from 'vue'

interface RowData {
  id: number
  name: string
  gender: string
  age: number
  time: string
}

const zTableRef = ref()
const radioData = ref({})
const selectionData = ref<RowData[]>([])
const tableData = ref([
  {
    id: 1,
    name: 'Steven',
    gender: 'male',
    age: 22,
    time: '2020-01-01',
  },
  {
    id: 2,
    name: 'Helen',
    gender: 'male',
    age: 12,
    time: '2012-01-01',
  },
  {
    id: 3,
    name: 'Nancy',
    gender: 'female',
    age: 18,
    time: '2018-01-01',
  },
  {
    id: 4,
    name: 'Jack',
    gender: 'male',
    age: 28,
    time: '2028-01-01',
  },
])

const columns = ref([
  {
    type: 'radio',
  },
  {
    type: 'selection',
  },
  {
    prop: 'name',
    label: 'Name',
  },
  {
    prop: 'gender',
    label: 'Gender',
  },
  {
    prop: 'age',
    label: 'Age',
  },
  {
    prop: 'time',
    label: 'Date',
  },
])

function handleRadioChange(row: RowData) {
  radioData.value = row
  console.log(row, 'radio data')
}

function handleSelectionChange(selection: RowData[]) {
  selectionData.value = selection
  console.log(selection, 'selection data')
}

function handleClear() {
  zTableRef.value.clearSelection()
}
</script>

<template>
  <el-button @click="handleClear">
    Clear selection
  </el-button>
  <z-crud
    ref="zTableRef"
    :data="tableData"
    :columns="columns"
    :action="false"
    @radio-change="handleRadioChange"
    @selection-change="handleSelectionChange"
  />
</template>

z-crud Table Attributes

AttributeDescriptionTypeAccepted ValuesDefault
modelValue:dataDisplay data, supports two-way bindingarray
modelValue:formDataQuery form data, supports two-way bindingarray
modelValue:paginationPagination configuration, supports two-way bindingobject
modelValue:loadingTable loading, supports two-way bindingboolean
modelValue:selectionCheckbox selected data, supports two-way bindingarray
columnsTable configuration itemsarray
toolBarToolbar configurationobject / boolean
editableEditable table configurationobject / boolean
optionsTable internal option data sourceobject
titleTable titlestring / function
totalDataAll table data (effective for frontend pagination)array
nameTable key, configuring name enables caching by defaultstring
paginationStoragePagination data cachingbooleanfalse
formStorageQuery form data cachingbooleanfalse
formDecoratorForm backgroundobject{ name: 'el-card' }
tableDecoratorTable backgroundobject{ name: 'el-card' }
watermarkWatermark configurationobject (see el-watermark documentation for details)
heightTable height, defaults to auto height. If height is number type, unit is px; if height is string type, this height will be set as Table's style.height value, Table height will be controlled by external styles.string / number
max-heightTable max height. Valid values are numbers or heights in px units.string / number
stripeWhether table is stripedbooleanfalse
borderWhether table has vertical bordersbooleanfalse
sizeTable sizestringlarge / default /small
fitWhether column width fits contentbooleantrue
show-headerWhether to show table headerbooleantrue
highlight-current-rowWhether to highlight current rowbooleanfalse
current-row-keyKey of current row, write-only propertystring / number
row-class-nameFunction for row className, can also use string to set fixed className for all rows.function({ row, rowIndex }) / string
row-styleFunction for row style, can also use fixed Object to set same Style for all rows.function({ row, rowIndex }) / object
cell-class-nameFunction for cell className, can also use string to set fixed className for all cells.function({ row, column, rowIndex, columnIndex }) / string
cell-styleFunction for cell style, can also use fixed Object to set same Style for all cells.function({ row, column, rowIndex, columnIndex }) / object
header-row-class-nameFunction for header row className, can also use string to set fixed className for all header rows.function({ row, rowIndex }) / string
header-row-styleFunction for header row style, can also use fixed Object to set same Style for all header rows.function({ row, rowIndex }) / object
header-cell-class-nameFunction for header cell className, can also use string to set fixed className for all header cells.function({ row, column, rowIndex, columnIndex }) / string
header-cell-styleFunction for header cell style, can also use fixed Object to set same Style for all header cells.function({ row, column, rowIndex, columnIndex }) / object
row-keyKey for row data, used to optimize Table rendering; required when using reserve-selection feature and displaying tree data. When type is String, supports multi-level access: user.info.id, but does not support user.info[0].id, use Function for this case.function(row) / string
empty-textText displayed when data is empty, can also be set through #empty slotstringNo Data
default-expand-allWhether to expand all rows by default, effective when Table contains expandable rows or is tree tablebooleanfalse
expand-row-keysSet currently expanded rows through this property, requires row-key property to be set, this property is an array of keys for expanded rows.array
default-sortDefault sort column prop and order. Its prop property specifies default sort column, order specifies default sort orderobject(order: 'ascending' 'descending')'descending')
tooltip-effecteffect of overflow tooltipstringdark / lightdark
tooltip-optionsOptions for overflow tooltip, see tooltip component belowobjectsee tooltipobject
show-summaryWhether to show summary row at table footerbooleanfalse
sum-textText for first column of summary rowstringSum
summary-methodCustom summary calculation methodfunction({ columns, data })
span-methodMethod for merging rows or columnsfunction({ row, column, rowIndex, columnIndex })
select-on-indeterminateBehavior when clicking header checkbox when only some rows are selected in multi-select table. If true, select all rows; if false, deselect all rowsbooleantrue
indentIndentation of tree nodes when displaying tree datanumber16
lazyWhether to lazy load child node databoolean
loadFunction for loading child node data, effective when lazy is truefunction(row, treeNode, resolve)
tree-propsConfiguration options for rendering nested dataobject{ hasChildren: 'hasChildren', children: 'children' }
table-layoutLayout method for table cells, rows and columnsstringfixed / autofixed
scrollbar-always-onAlways show scrollbarbooleanfalse
show-overflow-tooltipWhether to hide extra content and show them in Tooltip when cell content overflows. This will affect all columns.boolean / objectSee tooltip-options
flexibleEnsure minimum size of main axis to not exceed contentbooleanfalse

z-crud Table Events

Event NameDescriptionCallback Parameters
refreshEvent triggered when pagingpagination
radio-changeEvent triggered when user manually checks Radio of data rowrow
selectEvent triggered when user manually checks Checkbox of data rowselection, row
select-allEvent triggered when user manually checks select all Checkboxselection
selection-changeEvent triggered when selection changesselection
cell-mouse-enterEvent triggered when cell hover entersrow, column, cell, event
cell-mouse-leaveEvent triggered when cell hover leavesrow, column, cell, event
cell-clickEvent triggered when a cell is clickedrow, column, cell, event
cell-dblclickEvent triggered when a cell is double clickedrow, column, cell, event
cell-contextmenuEvent triggered when a cell is right clickedrow, column, cell, event
row-clickEvent triggered when a row is clickedrow, column, event
row-contextmenuEvent triggered when a row is right clickedrow, column, event
row-dblclickEvent triggered when a row is double clickedrow, column, event
header-clickEvent triggered when a column header is clickedcolumn, event
header-contextmenuEvent triggered when a column header is right clickedcolumn, event
sort-changeEvent triggered when table sort conditions change{ column, prop, order }
filter-changeColumn key, if you need to use filter-change event, this attribute is needed to identify which column's filter conditionfilters
current-changeEvent triggered when table's current row changes, if you want to highlight current row, please enable table's highlight-current-row attributecurrentRow, oldCurrentRow
header-dragendEvent triggered when dragging header changes column widthnewWidth, oldWidth, column, event
expand-changeEvent triggered when user expands or collapses a row (when expanding rows, second parameter is expandedRows; when tree table, second parameter is expanded)row, (expandedRows | expanded)

z-crud Table Methods

Method NameDescriptionParameters
getTableDataGet table data method
clearSelectionClear selection for multi-select table or single-select table
getSelectionRowsReturn currently selected rows
toggleRowSelectionToggle selection state of a row for multi-select table, can directly set selection state with second parameterrow, selected
toggleAllSelectionToggle select all and deselect all for multi-select table
toggleRowExpansionToggle row expansion for expandable table or tree table. Use second parameter to directly set expansion staterow, expanded
setCurrentRowSet a row as selected for single-select table, call without parameters to cancel current selectionrow
clearSortClear sort conditions, data will restore to unsorted state
clearFilterPass array of columnKey to clear filter conditions for specified columns. Clear all filters if no parameterscolumnKeys
doLayoutRe-layout Table. You may need to call this method when table visibility changes to get correct layout
sortSort table manually. prop parameter specifies sort column, order specifies sort order.prop: string, order: string
scrollToScroll to specific coordinates(options: ScrollToOptions | number, yCoord?: number)
setScrollTopSet vertical scroll positiontop
setScrollLeftSet horizontal scroll positionleft

z-crud Slots

Slot NameDescriptionSubtags
appendContent inserted after the last row of table. If table has summary row, this slot will be above summary row.
emptyCustom content when data is empty
tableTopTop slot
tableBottomBottom slot
toolBarTopToolbar top slot
toolBarBottomToolbar bottom slot
toolBarRightToolbar right slot
toolBarLeftToolbar left slot
tableTitleTable title slot
paginationTopPagination top slot
paginationBottomPagination bottom slot
paginationLeftPagination left slot
paginationRightPagination right slot
formTopForm top slot
formBottomForm bottom slot
crudMiddleMiddle content slot

columns Attributes

AttributeDescriptionTypeAccepted ValuesDefault
typeColumn type.stringselection / index / expand/ radio / button
componentColumn component type.stringinput / select / checkbox / radio / any locally or globally registered component
indexIf type=index is set, you can customize the index by passing the index attributenumber / function(index)
labelDisplay title (recommended to configure)string / (scope) => VNode
formForm configurationobject
addAdd form configurationobject / boolean
editEdit form configurationobject / boolean
searchSearch form configurationobject / boolean
detailDetail form configurationobject / boolean
buttonsButton configurationarray
optionsOption component data sourcearray
tooltipColumn tooltipstring / () => VNode
column-keyColumn key, if you need to use filter-change event, this attribute is needed to identify which column's filter conditionstring
propField name corresponding to column content, can also use property attributestring
widthColumn widthstring / number
min-widthColumn minimum width, difference with width is that width is fixed, min-width will distribute remaining width proportionally to columns with min-width setstring / number
fixedWhether column is fixed on left or right side. true means fixed on left sidestring / booleantrue / 'left' / 'right'
render-headerFunction for rendering column title Label areafunction({ column, $index })
sortableWhether column is sortable, if set to 'custom', it means user wants remote sorting, need to listen to Table's sort-change eventboolean / stringcustomfalse
sort-methodSpecify which property to sort by, only effective when sortable is set to true. Should return a Number like Array.sortfunction(a, b)
sort-bySpecify which property to sort by, only effective when sortable is true and sort-method is not set. If sort-by is array, sort by 1st property first, if equal, sort by 2nd, and so onfunction(row, index) / string / array
sort-ordersRotation order of sorting strategies used when sorting data, only effective when sortable is true. Need to pass an array, as user clicks table header, column will sort according to array elements in orderarrayArray elements need to be one of: ascending for ascending, descending for descending, null for original order['ascending', 'descending', null]
resizableWhether column width can be changed by dragging (need to set border attribute to true on el-table)booleantrue
formatterFunction for formatting contentfunction(row, column, cellValue, index)
show-overflow-tooltipWhether to show tooltip when content is too long and hiddenboolean / objectSee table's tooltip-options
alignAlignmentstringleft / center / rightleft
header-alignHeader alignment, if not set, use table's alignmentstringleft / center / right
class-nameColumn classNamestring
label-class-nameCustom class name for current column titlestring
selectableOnly effective for type=selection columns, type is Function, Function return value determines whether this row's CheckBox can be checkedfunction(row, index)
reserve-selectionWhether to reserve selection after data refresh, only effective for type=selection columns, note that you need to specify row-key for this feature to work.booleanfalse
filtersData filter options, array format, each element in array needs text and value properties. Each element in array needs text and value properties.Array<{text: string, value: string}>
filter-placementFilter popup positioningstringSame as Tooltip's placement attribute
filter-multipleWhether data filter options allow multiple selectionbooleantrue
filter-methodMethod for data filtering, if it's multi-select filter, it will execute multiple times for each data, will show if any execution returns true.function(value, row, column)
filtered-valueSelected data filter items, may be needed if you need to customize table header filter rendering.array
Event NameDescriptionCallback Parameters
refreshEvent triggered when pagingpagination
radio-changeEvent triggered when user manually checks Radio of data rowrow
selectEvent triggered when user manually checks Checkbox of data rowselection, row
select-allEvent triggered when user manually checks select all Checkboxselection
selection-changeEvent triggered when selection changesselection
cell-mouse-enterEvent triggered when cell hover entersrow, column, cell, event
cell-mouse-leaveEvent triggered when cell hover leavesrow, column, cell, event
cell-clickEvent triggered when a cell is clickedrow, column, cell, event
cell-dblclickEvent triggered when a cell is double clickedrow, column, cell, event
cell-contextmenuEvent triggered when a cell is right clickedrow, column, cell, event
row-clickEvent triggered when a row is clickedrow, column, event
row-contextmenuEvent triggered when a row is right clickedrow, column, event
row-dblclickEvent triggered when a row is double clickedrow, column, event
header-clickEvent triggered when a column header is clickedcolumn, event
header-contextmenuEvent triggered when a column header is right clickedcolumn, event
sort-changeEvent triggered when table sort conditions change{ column, prop, order }
filter-changeColumn key, if you need to use filter-change event, this attribute is needed to identify which column's filter conditionfilters
current-changeEvent triggered when table's current row changes, if you want to highlight current row, please enable table's highlight-current-row attributecurrentRow, oldCurrentRow
header-dragendEvent triggered when dragging header changes column widthnewWidth, oldWidth, column, event
expand-changeEvent triggered when user expands or collapses a row (when expanding rows, second parameter is expandedRows; when tree table, second parameter is expanded)row, (expandedRows | expanded)

z-crud Table Methods

Method NameDescriptionParameters
getTableDataGet table data method
clearSelectionClear selection for multi-select table or single-select table
getSelectionRowsReturn currently selected rows
toggleRowSelectionToggle selection state of a row for multi-select table, can directly set selection state with second parameterrow, selected
toggleAllSelectionToggle select all and deselect all for multi-select table
toggleRowExpansionToggle row expansion for expandable table or tree table. Use second parameter to directly set expansion staterow, expanded
setCurrentRowSet a row as selected for single-select table, call without parameters to cancel current selectionrow
clearSortClear sort conditions, data will restore to unsorted state
clearFilterPass array of columnKey to clear filter conditions for specified columns. Clear all filters if no parameterscolumnKeys
doLayoutRe-layout Table. You may need to call this method when table visibility changes to get correct layout
sortSort table manually. prop parameter specifies sort column, order specifies sort order.prop: string, order: string
scrollToScroll to specific coordinates(options: ScrollToOptions | number, yCoord?: number)
setScrollTopSet vertical scroll positiontop
setScrollLeftSet horizontal scroll positionleft

z-crud Slots

Slot NameDescriptionSubtags
appendContent inserted after the last row of table. If table has summary row, this slot will be above summary row.
emptyCustom content when data is empty
tableTopTop slot
tableBottomBottom slot
toolBarTopToolbar top slot
toolBarBottomToolbar bottom slot
toolBarRightToolbar right slot
toolBarLeftToolbar left slot
tableTitleTable title slot
paginationTopPagination top slot
paginationBottomPagination bottom slot
paginationLeftPagination left slot
paginationRightPagination right slot
formTopForm top slot
formBottomForm bottom slot
crudMiddleMiddle content slot

button type dropdown Attributes

AttributeDescriptionTypeAccepted ValuesDefault
referenceReference textstring / (scope) => VNodeMore
onCommandEvent callback triggered when menu item is clicked(command) => void
typeMenu button type, same as Button component, only effective when split-button is true.string
sizeMenu size, also affects trigger button when split-button is true.stringlarge / default / smalldefault
max-heightMaximum height of menustring / number
split-buttonWhether dropdown trigger element is presented as button groupbooleanfalse
disabledWhether disabledbooleanfalse
placementMenu popup positionstringtop/top-start/top-end/bottom/bottom-start/bottom-endbottom
triggerBehavior to trigger dropdownstringhover / click /contextmenuhover
hide-on-clickWhether to hide menu after clicking menu itembooleantrue
show-timeoutDelay before showing dropdown menu, only effective when trigger is hovernumber250
hide-timeoutDelay before hiding dropdown menu (only effective when trigger is hover)number150
roleARIA attribute for dropdown menu. You might want to change this to "navigation" based on specific scenariosstring'menu'
tabindextabindex for Dropdown componentnumber0
popper-classCustom class name for popperstring
popper-optionspopper.js parametersObjectSee popper.js documentation{modifiers: [{name: 'computeStyles',options: {gpuAcceleration: false}}]}
teleportedWhether to insert dropdown list to body elementbooleantrue
AttributeDescriptionTypeAccepted ValuesDefault
disabledWhether disabledboolean / ({ row, $index, column }) => booleanfalse
onClickDropdown item click({ row, $index, column }) => void
dividedWhether to show dividerbooleanfalse
iconCustom iconstring / Component

toolBar Attributes

AttributeDescriptionTypeAccepted ValuesDefault
excludeTable item label collection not shown in toolbararray
unCheckDefault unchecked label collectionarray
refreshWhether refresh feature is displayedbooleantrue
densityWhether density feature is displayedbooleantrue
fullScreenWhether fullscreen feature is displayedbooleantrue
settingWhether column setting feature is displayedbooleantrue

Released under the MIT License.