Files
ui/docs/content/3.forms/10.form.md
2023-10-10 18:48:07 +02:00

175 lines
5.7 KiB
Markdown

---
description: Collect and validate form data.
links:
- label: GitHub
icon: i-simple-icons-github
to: 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](https://github.com/jquense/yup), [Zod](https://github.com/colinhacks/zod), [Joi](https://github.com/hapijs/joi), [Valibot](https://valibot.dev/) 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": "space-y-4 w-60"}'}
## Schema
You can provide a schema from [Yup](#yup), [Zod](#zod) or [Joi](#joi), [Valibot](#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": "space-y-4 w-60"}'}
### Zod
:component-example{component="form-example-zod" :componentProps='{"class": "space-y-4 w-60"}'}
### Joi
:component-example{component="form-example-joi" :componentProps='{"class": "space-y-4 w-60"}'}
### Valibot
:component-example{component="form-example-valibot" :componentProps='{"class": "space-y-4 w-60"}'}
## Other libraries
For other validation libraries, you can define your own component with custom validation logic.
Here is an example with [Vuelidate](https://github.com/vuelidate/vuelidate):
```vue
<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.
```vue
<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.
:component-example{component="form-example-elements" :componentProps='{"class": "space-y-4 w-60"}' hiddenCode }
::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 :u-badge{label="New" class="align-middle ml-2 !rounded-full" variant="subtle"}
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": "space-y-4 w-60"}'}
## Props
:component-props
## API
::field-group
::field{name="validate (path?: string, opts: { silent?: boolean })" type="Promise<T>"}
Triggers form validation. Will raise any errors unless `opts.silent` is set to true.
::
::field{name="clear (path?: string)" type="void"}
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)" type="void"}
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.
::
::