Files
ui/docs/content/2.components/form.md
Benjamin Canac e92be71749 docs: new structure (#1282)
Co-authored-by: Sébastien Chopin <seb@nuxt.com>
2024-01-30 11:24:02 +01:00

6.1 KiB

description, links
description links
Collect and validate form data.
label icon to
GitHub i-simple-icons-github https://github.com/nuxt/ui/blob/dev/src/runtime/components/forms/Form.vue

Usage

Use the Form component to validate form data using schema libraries such as Yup, Zod, Joi, Valibot or your own validation logic. It works seamlessly with the FormGroup component to automatically display error messages around form elements.

The Form component requires the validate and state props for form validation.

  • state - a reactive object that holds the current state of the form.
  • validate - a function that takes the form's state as input and returns an array of FormError objects with the following fields:
    • message - the error message to display.
    • path - the path to the form element matching the name.

::component-example

component: 'form-example-basic' componentProps: class: 'w-60'

::

Schema

You can provide a schema from Yup, Zod or Joi, Valibot through the schema prop to validate the state. It's important to note that none of these libraries are included by default, so make sure to install the one you need.

Yup

::component-example

component: 'form-example-yup' componentProps: class: 'w-60'

::

Zod

::component-example

component: 'form-example-zod' componentProps: class: 'w-60'

::

Joi

::component-example

component: 'form-example-joi' componentProps: class: 'w-60'

::

Valibot

::component-example

component: 'form-example-valibot' componentProps: class: 'w-60'

::

Other libraries

For other validation libraries, you can define your own component with custom validation logic.

Here is an example with Vuelidate:

<script setup lang="ts">
import useVuelidate from '@vuelidate/core'

const props = defineProps({
  rules: { type: Object, required: true },
  model: { type: Object, required: true }
})

const form = ref();
const v = useVuelidate(props.rules, props.model)

async function validateWithVuelidate() {
  v.value.$touch()
  await v.value.$validate()
  return v.value.$errors.map((error) => ({
    message: error.$message,
    path: error.$propertyPath,
  }))
}

defineExpose({
  validate: async () => {
    await form.value.validate()
  }
})
</script>

<template>
  <UForm ref="form" :model="model" :validate="validateWithVuelidate">
    <slot />
  </UForm>
</template>

Backend validation

You can manually set errors after form submission if required. To do this, simply use the form.setErrors function to set the errors as needed.

<script setup lang="ts">
import type { FormError, FormSubmitEvent } from '#ui/types'

const state = reactive({
  email: undefined,
  password: undefined
})

const form = ref()

async function onSubmit (event: FormSubmitEvent<any>) {
  form.value.clear()
  try {
    const response = await $fetch('...')
    // ...
  } catch (err) {
    if (err.statusCode === 422) {
      form.value.setErrors(err.data.errors.map((err) => {
        // Map validation errors to { path: string, message: string }
      }))
    }
  }
}
</script>

<template>
  <UForm ref="form" :state="state" @submit="onSubmit">
    <UFormGroup label="Email" name="email">
      <UInput v-model="state.email" />
    </UFormGroup>

    <UFormGroup label="Password" name="password">
      <UInput v-model="state.password" type="password" />
    </UFormGroup>

    <UButton type="submit">
      Submit
    </UButton>
  </UForm>
</template>

Input events

The Form component automatically triggers validation upon submit, input, blur or change events. This ensures that any errors are displayed as soon as the user interacts with the form elements. You can control when validation happens this using the validate-on prop.

::callout{icon="i-heroicons-light-bulb"} Note that the input event is not triggered until after the initial blur event. This is to prevent the form from being validated as the user is typing. You can override this behavior by setting the eager-validation prop on FormGroup to true. ::

::component-example

component: 'form-example-elements' componentProps: class: 'w-60' hiddenCode: true

::

::callout{icon="i-simple-icons-github" to="https://github.com/nuxt/ui/blob/dev/docs/components/content/examples/FormExampleElements.vue" target="_blank"} Take a look at the component! ::

Error event

You can listen to the @error event to handle errors. This event is triggered when the form is validated and contains an array of FormError objects with the following fields:

  • id - the identifier of the form element.
  • path - the path to the form element matching the name.
  • message - the error message to display.

Here is an example of how to focus the first form element with an error:

::component-example

component: 'form-example-on-error' componentProps: class: 'w-60'

::

Props

:component-props

API

When accessing the component via a template ref, you can use the following:

::field-group ::field{name="submit ()" type="Promise"} Triggers form submission. :: ::field{name="validate (path?: string | string[], opts: { silent?: boolean })" type="Promise"} Triggers form validation. Will raise any errors unless opts.silent is set to true. :: ::field{name="clear (path?: string)"} Clears form errors associated with a specific path. If no path is provided, clears all form errors. :: ::field{name="getErrors (path?: string)" type="FormError[]"} Retrieves form errors associated with a specific path. If no path is provided, returns all form errors. :: ::field{name="setErrors (errors: FormError[], path?: string)"} Sets form errors for a given path. If no path is provided, overrides all errors. :: ::field{name="errors" type="Ref<FormError[]>"} A reference to the array containing validation errors. Use this to access or manipulate the error information. :: ::