Typed CRUD form lifecycle for Vue 2.7 and Vue 3. Keep the existing Element Plus, element-ui, Naive UI, or Ant Design Vue Form; one typed form instance owns create/edit/detail, validation, API errors, reset baselines, linkage, and dynamic rows.
Live examples · Guide · API · Discussions
pnpm add @vformjs/element-plus element-plus vue # Vue 3
# pnpm add @vformjs/element-ui element-ui vue@^2.7 # Vue 2.7
# pnpm add @vformjs/naive-ui naive-ui vue
# pnpm add @vformjs/ant-design-vue ant-design-vue vue| Package | Role |
|---|---|
@vformjs/element-plus |
Vue 3 + Element Plus — start here |
@vformjs/element-ui |
Vue 2.7 + element-ui |
@vformjs/naive-ui |
Vue 3 + Naive UI |
@vformjs/ant-design-vue |
Vue 3 + Ant Design Vue |
@vformjs/vue |
useForm / defineAdapter for custom UI |
@vformjs/zod |
Zod schema bridge |
@vformjs/core |
Headless engine (transitive) |
import { r, submitFail, useElForm } from '@vformjs/element-plus'
const form = useElForm({
defaults: { name: '', email: '' },
rules: {
name: [r.required(), r.min(2)],
email: [r.required(), r.email()],
},
onSubmit: async (values) => {
const result = await api.save(values)
if (!result.ok)
return submitFail(result.error, { errors: result.fieldErrors })
},
})<template>
<el-form v-bind="form.host" label-width="100px">
<el-form-item label="Name" v-bind="form.item('name')">
<el-input v-model="form.model.name" />
</el-form-item>
<el-form-item label="Email" prop="email">
<el-input v-model="form.model.email" />
</el-form-item>
<el-button type="primary" :loading="form.submitting" @click="form.submit()">
Submit
</el-button>
</el-form>
</template>form.host is { ref, model, rules }. form.item(path) supplies host-specific field props and errors.
onSubmit may return submitFail(error, { errors }); the error stays typed as
result.submitError, and field errors become reactive form.errors.
- Modes —
form.load('create' | 'edit' | 'detail', values?)in the dialog/page, not the list - Trust state — reactive
errors,dirty,changedPaths, and server-error scrolling - Submit failures — typed
submitErrorvalues with optional field errors - Rules —
r.required(), email, min/max, pattern, custom; or a function of values - when / whenRules — show/hide and conditional rules
- linkage — react when other fields change
- list / fieldArray — dynamic rows with stable keys
- Zod —
useZodForm({ schema, defaults })from@vformjs/element-plus/zod - Adapters — swap UI without rewriting form logic
| Link | Content |
|---|---|
| Live examples | Real Element Plus CRUD, conditional linkage, and dynamic array + Zod flows |
| Guide | Install, bind the host Form, modes, rules, arrays, Zod, adapters |
| Vue 2.7 → Vue 3 | Stable form contracts, safe codemod scope, dry-run, and manual review report |
| API | Options, return types, r.*, linkage, and adapter contracts |
| Integration feedback | Report a completed or blocked real-project adoption |
pnpm dlx vformjs init
pnpm dlx vformjs add form profile
pnpm dlx vformjs audit forms --json
pnpm dlx vformjs doctor
pnpm dlx vformjs migrate vue2-to-vue3 --dry-run --json
pnpm dlx vformjs skill installHost and Zod detection come from package.json. Generated modules use form.host, form.item(path), typed paths, localized rules, and typed submit outcomes; Zod imports only the /zod subpath. Output is idempotent, and edited files are never replaced without --force. Use --dry-run --json in coding-agent loops.
Private/company UI packages are never auto-detected. Configure their generated
import and factory explicitly with --adapter-package and --form-factory;
runtime integration remains a business-owned defineAdapter wrapper.
pnpm install
pnpm test
pnpm docs:dev # product site + docs
pnpm docs:build
pnpm dev:vue3 # Element Plus playground
pnpm dev:vue2
pnpm dev:naive
pnpm dev:antd