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

    enhancementNew feature or requestv3#1289

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions