Skip to content

[Form] Composable to generate state based on a standard schema #3876

Open
@MuhammadM1998

Description

@MuhammadM1998

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions