Skip to content

CollapseForm

Based on ZForm component and ElCollapse component encapsulation.

Basic Usage

Pass collapse to form type type, configure children (form items) in column items to implement collapsible form.

activeCollapse binds the expanded collapse item label. If you don't want to bind label, please configure field key in column item.

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

const activeCollapse = ref(['Text', 'Title'])
const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  time: [],
})

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

const columns = [
  {
    label: 'Text',
    children: [
      {
        component: 'input',
        field: 'name',
        modifier: 'trim',
        label: 'Name',
        onInput: (val: string) => {
          console.log(val, 'input event')
        },
        onChange: (val: string) => {
          console.log(val, 'change event')
        },
        rules: {
          required: true,
        },
      },
    ],
  },
  {
    label: 'Title',
    children: [
      {
        component: 'select',
        field: 'gender',
        label: 'Gender',
        md: 12,
        onChange: (val: string) => {
          console.log(val, 'change event')
        },
        onFocus: () => {
          console.log('focus event')
        },
      },
      {
        component: 'el-date-picker',
        field: 'time',
        label: 'Date',
        md: 12,
        fieldProps: {
          type: 'daterange',
          startPlaceholder: 'Start date',
          endPlaceholder: 'End date',
        },
        onChange: (val: string) => {
          console.log(val, 'change event')
        },
      },
    ],
  },
  {
    slot: 'operate',
  },
]

function reset() {
  formRef.value.resetFields()
}

function submit() {
  formRef.value.validate((valid: boolean) => {
    if (valid) {
      ElMessage.success('Success')
      console.log(formData.value, 'config.formData')
    }
    else {
      console.log('error submit!!')
      return false
    }
  })
}
</script>

<template>
  <z-form
    ref="formRef"
    v-model="formData"
    v-model:activeCollapse="activeCollapse"
    :options="options"
    :columns="columns"
    label-width="80px"
    size="default"
    type="collapse"
  >
    <template #operate>
      <div class="mt-4 w-full flex">
        <el-button class="w-full" @click="reset">
          Reset
        </el-button>
        <el-button class="w-full" type="primary" @click="submit">
          Submit
        </el-button>
      </div>
    </template>
  </z-form>
</template>

Title

By default, the label field of column item is the name of collapse item. If label is a function or you don't want to use label as collapse item name, please pass additional key field. Supports slot for custom title.

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

const activeCollapse = ref(['bbb', 'labelSlot'])
const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  time: [],
})

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

const columns = [
  {
    label: () => h('span', {}, 'Text A'),
    key: 'bbb',
    children: [
      {
        component: 'input',
        field: 'name',
        modifier: 'trim',
        label: 'Name',
        onInput: (val: string) => {
          console.log(val, 'input event')
        },
        onChange: (val: string) => {
          console.log(val, 'change event')
        },
        rules: {
          required: true,
        },
      },
    ],
  },
  {
    label: 'labelSlot',
    children: [
      {
        component: 'select',
        field: 'gender',
        label: 'Gender',
        md: 12,
        onChange: (val: string) => {
          console.log(val, 'change event')
        },
        onFocus: () => {
          console.log('focus event')
        },
      },
      {
        component: 'el-date-picker',
        field: 'time',
        label: 'Date',
        md: 12,
        fieldProps: {
          type: 'daterange',
          startPlaceholder: 'Start date',
          endPlaceholder: 'End date',
        },
        onChange: (val: string) => {
          console.log(val, 'change event')
        },
      },
    ],
  },
  {
    slot: 'operate',
  },
]

function reset() {
  formRef.value.resetFields()
}

function submit() {
  formRef.value.validate((valid: boolean) => {
    if (valid) {
      ElMessage.success('Success')
      console.log(formData.value, 'config.formData')
    }
    else {
      console.log('error submit!!')
      return false
    }
  })
}
</script>

<template>
  <z-form
    ref="formRef"
    v-model="formData"
    v-model:activeCollapse="activeCollapse"
    :options="options"
    :columns="columns"
    label-width="80px"
    size="default"
    type="collapse"
  >
    <template #labelSlot>
      <span>Label custom slot</span>
    </template>
    <template #operate>
      <div class="mt-4 w-full flex">
        <el-button class="w-full" @click="reset">
          Reset
        </el-button>
        <el-button class="w-full" type="primary" @click="submit">
          Submit
        </el-button>
      </div>
    </template>
  </z-form>
</template>

Collapse Attributes

accordion attribute is passed directly to ZForm component. disabled attribute is passed in column item to disable collapse item.

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

const activeCollapse = ref('Text')
const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  time: [],
})

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

const columns = [
  {
    label: 'Text',
    children: [
      {
        component: 'input',
        field: 'name',
        modifier: 'trim',
        label: 'Name',
        onInput: (val: string) => {
          console.log(val, 'input event')
        },
        onChange: (val: string) => {
          console.log(val, 'change event')
        },
        rules: {
          required: true,
        },
      },
    ],
  },
  {
    label: 'Title',
    children: [
      {
        component: 'select',
        field: 'gender',
        label: 'Gender',
        md: 12,
        onChange: (val: string) => {
          console.log(val, 'change event')
        },
        onFocus: () => {
          console.log('focus event')
        },
      },
      {
        component: 'el-date-picker',
        field: 'time',
        label: 'Date',
        md: 12,
        fieldProps: {
          type: 'daterange',
          startPlaceholder: 'Start date',
          endPlaceholder: 'End date',
        },
        onChange: (val: string) => {
          console.log(val, 'change event')
        },
      },
    ],
  },
  {
    label: 'Disabled',
    disabled: true,
    children: [
      {
        component: 'input',
        field: 'disabled',
        label: 'Disabled',
      },
    ],
  },
  {
    slot: 'operate',
  },
]

function reset() {
  formRef.value.resetFields()
}

function submit() {
  formRef.value.validate((valid: boolean) => {
    if (valid) {
      ElMessage.success('Success')
      console.log(formData.value, 'config.formData')
    }
    else {
      console.log('error submit!!')
      return false
    }
  })
}
</script>

<template>
  <z-form
    ref="formRef"
    v-model="formData"
    v-model:activeCollapse="activeCollapse"
    :options="options"
    :columns="columns"
    label-width="80px"
    size="default"
    type="collapse"
    accordion
  >
    <template #operate>
      <div class="mt-4 w-full flex">
        <el-button class="w-full" @click="reset">
          Reset
        </el-button>
        <el-button class="w-full" type="primary" @click="submit">
          Submit
        </el-button>
      </div>
    </template>
  </z-form>
</template>

Custom Content

When ZForm component type attribute is collapse, column item can configure slot or render to customize collapse content.

TIP

When column item passes children field (regardless of array length), it will render ElCollapse collapse item

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

const activeCollapse = ref(['Text', 'Title'])
const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  address: '',
  input: '',
  time: [],
})

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

const columns = [
  {
    label: 'Text',
    children: [
      {
        component: 'input',
        field: 'name',
        modifier: 'trim',
        label: 'Name',
        required: true,
      },
    ],
  },
  {
    label: 'Title',
    render: () => h('span', 'custom content'),
    children: [],
  },
  {
    label: 'Address',
    slot: 'addressSlot',
  },
  {
    label: 'Input',
    slot: 'input',
    required: true,
    message: 'Please enter text',
  },
  {
    slot: 'operate',
  },
]

function reset() {
  formRef.value.resetFields()
}

function submit() {
  formRef.value.validate((valid: boolean) => {
    if (valid) {
      ElMessage.success('Success')
      console.log(formData.value, 'config.formData')
    }
    else {
      console.log('error submit!!')
      return false
    }
  })
}
</script>

<template>
  <z-form
    ref="formRef"
    v-model="formData"
    v-model:activeCollapse="activeCollapse"
    :options="options"
    :columns="columns"
    label-width="80px"
    size="default"
    type="collapse"
  >
    <template #addressSlot>
      <div>Custom address</div>
    </template>
    <template #input>
      <ElInput v-model="formData.input" />
    </template>
    <template #operate>
      <div class="mt-4 w-full flex">
        <el-button class="w-full" @click="reset">
          Reset
        </el-button>
        <el-button class="w-full" type="primary" @click="submit">
          Submit
        </el-button>
      </div>
    </template>
  </z-form>
</template>

Collapse Expand Event

collapse-change event returns currently expanded collapse item label, bind directly to ZForm component.

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

const activeCollapse = ref(['Text', 'Title'])
const formRef = ref()
const formData = ref({
  name: '',
  gender: '',
  time: [],
})

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

const columns = [
  {
    label: 'Text',
    children: [
      {
        component: 'input',
        field: 'name',
        modifier: 'trim',
        label: 'Name',
        onInput: (val: string) => {
          console.log(val, 'input event')
        },
        onChange: (val: string) => {
          console.log(val, 'change event')
        },
        rules: {
          required: true,
        },
      },
    ],
  },
  {
    label: 'Title',
    children: [
      {
        component: 'select',
        field: 'gender',
        label: 'Gender',
        md: 12,
        onChange: (val: string) => {
          console.log(val, 'change event')
        },
        onFocus: () => {
          console.log('focus event')
        },
      },
      {
        component: 'el-date-picker',
        field: 'time',
        label: 'Date',
        md: 12,
        fieldProps: {
          type: 'daterange',
          startPlaceholder: 'Start date',
          endPlaceholder: 'End date',
        },
        onChange: (val: string) => {
          console.log(val, 'change event')
        },
      },
    ],
  },
  {
    slot: 'operate',
  },
]

function reset() {
  formRef.value.resetFields()
}

function submit() {
  formRef.value.validate((valid: boolean) => {
    if (valid) {
      ElMessage.success('Success')
      console.log(formData.value, 'config.formData')
    }
    else {
      console.log('error submit!!')
      return false
    }
  })
}

function handleCollapseChange(val: string) {
  console.log(val, 'val')
}
</script>

<template>
  <z-form
    ref="formRef"
    v-model="formData"
    v-model:activeCollapse="activeCollapse"
    :options="options"
    :columns="columns"
    label-width="80px"
    size="default"
    type="collapse"
    @collapse-change="handleCollapseChange"
  >
    <template #operate>
      <div class="mt-4 w-full flex">
        <el-button class="w-full" @click="reset">
          Reset
        </el-button>
        <el-button class="w-full" type="primary" @click="submit">
          Submit
        </el-button>
      </div>
    </template>
  </z-form>
</template>

Collapse Form Attributes

AttributeDescriptionTypeDefault
v-model:activeCollapseExpanded collapse items (effective when type is collapse)array / string
accordionAccordion modebooleanfalse

Events

Event NameDescriptionType
update:modelValueForm item dataFunction
update:activeCollapseExpanded items of collapse formFunction
collapse-changeTriggered when collapse item changesFunction

Released under the MIT License.