Description
Description
Hey!
Currently, the form component requires defining a schema
and a state
. This means we need to duplicate each form field twice.
<script setup lang="ts">
import * as z from 'zod'
const schema = z.object({
email: z.string().email('Invalid email'),
password: z.string().min(8, 'Must be at least 8 characters')
})
type Schema = z.output<typeof schema>
// We have to repeat the keys again to define the state
const state = reactive<Partial<Schema>>({
email: undefined,
password: undefined
})
</script>
<template>
<UForm :schema :state>
...
</UForm>
</template>
Proposed Solution
Having a composable similar to that takes a standard validation object and returns both the schema and state will be much better DX. Below is the refactored version of the above example using the requested composable.
<script setup lang="ts">
import * as z from 'zod'
// Both `state` and `schema` are typed. `state` is also reactive
const { state, schema } = useForm({
schema: {
email: z.string().email('Invalid email'),
password: z.string().min(8, 'Must be at least 8 characters')
},
initialValues, {
email: '[email protected]'
}
})
</script>
<template>
<UForm :schema :state>
...
</UForm>
</template>
VeeValidate
This is similar to how useForm
and toTypedSchema
composables from VeeValidate (source)
import { useForm } from 'vee-validate';
import { object, string } from 'zod';
import { toTypedSchema } from '@vee-validate/zod';
// `values` is the equivalent of `state` in nuxt/ui
const { values } = useForm({
validationSchema: toTypedSchema(
object({
email: z.string().email('Invalid email'),
password: z.string().min(8, 'Must be at least 8 characters')
}),
),
});
The problem with integrating VeeValidate instead of a built-in helper is the values
ref. It's the equivalent of state
ref in nuxt/ui, which we pass to the UForm
component to be mutated. VeeValidate discourages mutating values
directly (docs).
Possible Workaround
Provide docs on how to integrate VeeValidate or similar libraries that return a typed schema and a state ref in one go.
Additional context
No response