@chemical-x/forms
v0.13.0
Published
A fully type-safe, schema-driven form library that gives you superpowers. Chemical X included.
Maintainers
Readme
Chemical X Forms
A schema-driven form library for Vue 3 and Nuxt. Bring a Zod schema (or your own validator); useForm returns typed reads, writes, errors, and a submit handler. Every path, value, and error is inferred from the schema — no any, no string keys.
Installation
npm install @chemical-x/forms zodNuxt 3 / 4 — install the module:
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@chemical-x/forms/nuxt'],
})Bare Vue 3 — install the plugin and the Vite plugin:
// main.ts
import { createApp } from 'vue'
import { createChemicalXForms } from '@chemical-x/forms'
createApp(App).use(createChemicalXForms()).mount('#app')// vite.config.ts
import vue from '@vitejs/plugin-vue'
import { chemicalXForms } from '@chemical-x/forms/vite'
export default defineConfig({
plugins: [vue(), chemicalXForms()],
})Quick start
<script setup lang="ts">
import { z } from 'zod'
import { useForm } from '@chemical-x/forms/zod' // zod v4; use /zod-v3 for v3
const schema = z.object({
email: z.email(),
password: z.string().min(8),
})
const form = useForm({ schema, key: 'signup' })
const onSubmit = form.handleSubmit(async (values) => {
await $fetch('/api/signup', { method: 'POST', body: JSON.stringify(values) })
})
</script>
<template>
<form @submit.prevent="onSubmit">
<input v-register="form.register('email')" placeholder="Email" />
<small v-if="form.errors.email?.[0]">{{ form.errors.email[0].message }}</small>
<input v-register="form.register('password')" type="password" placeholder="Password" />
<small v-if="form.errors.password?.[0]">{{ form.errors.password[0].message }}</small>
<button :disabled="form.state.isSubmitting">Sign up</button>
</form>
</template>useForm({ schema, key }) returns a Pinia-style reactive object — read leaves directly, no .value:
form.values— current values.form.values.email,form.values.address.city.form.errors— per-field errors, keyed by dotted path.form.errors.email?.[0]?.message.form.fieldState— per-field flags (dirty,touched,errors,blank, …).form.fieldState.email.dirty.form.state— form-level flags (isSubmitting,isValid,canUndo, …).form.register(path)— typed two-way binding; pair withv-registeron<input>/<textarea>/<select>.form.handleSubmit(onValid, onInvalid?)— runs validation, dispatches. The valid callback receives the strict zod-inferred type.form.setValue(path, value),form.reset(), field-array helpers, undo / redo, persistence — see the API reference.
Features
- Schema-driven types — every path, value, and error is inferred from the schema; no
any. - Live validation — debounced
'change'by default;'blur'and'none'available; async refinements await before submit dispatches. - Field arrays —
append/prepend/insert/remove/swap/move/replace, fully typed at the call site. - Drafts + undo / redo — per-field opt-in persistence (
localStorage/sessionStorage/ IndexedDB / custom backend) and a bounded undo stack. - Server errors —
parseApiErrors(payload)normalises a{ message, code }[]wire format; pair withform.setFieldErrors(...). User errors survive schema revalidation. - Stable error codes — every
ValidationErrorcarriescode: string. Library codes (cx:) live on the exportedCxErrorCodeenum; adapter codes use azod:prefix; consumers pick their own (api:,auth:, …). - Clearable required fields — the
unsetsentinel marks a field displayed-empty while storage holds the schema's slim default. Submit fails with'No value supplied'for required schemas;.optional()/.nullable()/.default(N)opt out. - SSR — Nuxt handles the payload round-trip automatically; bare Vue uses
renderChemicalXState/hydrateChemicalXState(recipe).
Documentation
- API reference — every public export with signatures and return shapes
- Recipes — task-oriented walkthroughs for every feature above
- Troubleshooting — common gotchas and fixes
- Migration guides — per-release upgrade notes
- Performance — how it scales; when to worry
- Changelog — full release history
Status
Pre-1.0. SemVer applies from v1.0 onward; 0.x minor bumps may still include breaking changes, each documented under docs/migration/.
License
MIT — see LICENSE.
