Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
MuhammadM1998 opened this issue Apr 13, 2025 · 0 comments
Open

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

MuhammadM1998 opened this issue Apr 13, 2025 · 0 comments
Labels
enhancement New feature or request triage v3 #1289

Comments

@MuhammadM1998
Copy link
Contributor

MuhammadM1998 commented Apr 13, 2025

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: 'foo@bar.com'
    }
  })
</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

@MuhammadM1998 MuhammadM1998 added enhancement New feature or request triage v3 #1289 labels Apr 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request triage v3 #1289
Projects
None yet
Development

No branches or pull requests

1 participant