nuxt-formisch

Nuxt Formisch
Type-safe, headless forms for Nuxt with Formisch and Valibot, plus an optional Nuxt UI AutoForm.
Formisch is a small, schema-based form library: you describe a form with a Valibot schema and get typed values, field state and validation. This module auto-imports its composables, components and methods, validates request bodies in server routes with the same schema, and, with Nuxt UI installed, renders a whole form from a schema with <FAutoForm>.
Quick start
pnpm add nuxt-formisch valibot// nuxt.config.ts
export default defineNuxtConfig({
modules: ['nuxt-formisch'],
})Define the schema in shared/utils/, where both the app and the server auto-import it:
// shared/utils/schemas.ts
import * as v from 'valibot'
export const LoginSchema = v.object({
email: v.pipe(v.string(), v.email()),
password: v.pipe(v.string(), v.minLength(8)),
})Build the form. useForm, <FForm> and <FField> are auto-imported:
<!-- app/pages/login.vue -->
<script setup lang="ts">
const form = useForm({ schema: LoginSchema })
const login: SubmitHandler<typeof LoginSchema> = values =>
$fetch('/api/login', { method: 'POST', body: values })
</script>
<template>
<FForm :of="form" @submit="login">
<FField v-slot="field" :of="form" :path="['email']">
<input v-model="field.input" v-bind="field.props" type="email">
<p v-if="field.errors">{{ field.errors[0] }}</p>
</FField>
<FField v-slot="field" :of="form" :path="['password']">
<input v-model="field.input" v-bind="field.props" type="password">
<p v-if="field.errors">{{ field.errors[0] }}</p>
</FField>
<button :disabled="form.isSubmitting">Log in</button>
</FForm>
</template>Validate the same body on the server. readValidatedFormBody returns the typed output or throws a 400 with the issues:
// server/api/login.post.ts
export default defineEventHandler(async (event) => {
const { email } = await readValidatedFormBody(event, LoginSchema)
return { email }
})With Nuxt UI in modules, <FAutoForm> renders the inputs, labels, errors and submit button from the schema:
<FAutoForm :schema="LoginSchema" @submit="login" />Docs
- Getting started: install, first form, configuration
- Forms: composables, methods, components, server validation
- AutoForm: usage, customization, theming
- Migrating from 0.0.x
Develop
pnpm install
pnpm dev:prepare # stub the module and prepare the playground
pnpm dev # the playground in playground/
pnpm test
pnpm lint
pnpm typecheck
pnpm check:doctor # vite-doctor
pnpm validate # build the module and run publintThe docs site in docs/ is a separate project with its own lockfile:
cd docs
pnpm install
pnpm dev
pnpm og # redraw docs/public/og/*.pngRelease
Releases are cut by uppt from conventional commits. Every push to main opens or updates a draft release PR with the next version and changelog. Merging it tags the release and publishes the package to npm.