# use-form
Package: @mantine/form
Import: import { use-form } from '@mantine/form';
Description: Manage form state

## Installation

The `@mantine/form` package does not depend on any other libraries. You can use it with or without `@mantine/core` inputs:

```bash
yarn add @mantine/form
```

```bash
npm install @mantine/form
```

## Usage

```tsx
import { Button, Checkbox, Group, TextInput } from '@mantine/core';
import { useForm } from '@mantine/form';

function Demo() {
  const form = useForm({
    mode: 'uncontrolled',
    initialValues: {
      email: '',
      termsOfService: false,
    },

    validate: {
      email: (value) => (/^\\S+@\\S+$/.test(value) ? null : 'Invalid email'),
    },
  });

  return (
    <form onSubmit={form.onSubmit((values) => console.log(values))}>
      <TextInput
        withAsterisk
        label="Email"
        placeholder="your@email.com"
        key={form.key('email')}
        {...form.getInputProps('email')}
      />

      <Checkbox
        mt="md"
        label="I agree to sell my privacy"
        key={form.key('termsOfService')}
        {...form.getInputProps('termsOfService', { type: 'checkbox' })}
      />

      <Group justify="flex-end" mt="md">
        <Button type="submit">Submit</Button>
      </Group>
    </form>
  );
}
```


## API overview

All examples below use the following example use-form hook.

```tsx
import { useForm } from '@mantine/form';

const form = useForm({
  mode: 'uncontrolled',
  initialValues: {
    path: '',
    path2: '',
    user: {
      firstName: 'John',
      lastName: 'Doe',
    },
    fruits: [
      { name: 'Banana', available: true },
      { name: 'Orange', available: false },
    ],
    accepted: false,
  },
});
```

### Values

[Form values guide](https://mantine.dev/llms/form-values.md)

```tsx
// get the current form values
form.getValues();

// Set all form values
form.setValues(values);

// Set all form values using the previous state
form.setValues((prev) => ({ ...prev, ...values }));

// Set the value of a single field
form.setFieldValue('path', value);

// Set the value of a nested field
form.setFieldValue('user.firstName', 'Jane');

// Resets form values to `initialValues`,
// clears all validation errors,
// resets touched and dirty state
form.reset();

// Reset the field at `path` to its initial value
form.resetField('path');

// Sets initial values, used when the form is reset
form.setInitialValues({ values: 'object' });
```

### List items

[Nested fields guide](https://mantine.dev/llms/form-nested.md)

```tsx
// Inserts the given list item at the specified path
form.insertListItem('fruits', { name: 'Apple', available: true });

// An optional index may be provided to specify the position in a nested field.
// If the index is provided, the item will be inserted at the given position.
// If the index is larger than the current list, the element is inserted at the last position.
form.insertListItem('fruits', { name: 'Orange', available: true }, 1);

// Removes the list item at the specified path and index.
form.removeListItem('fruits', 1);

// Replaces the list item at the specified path and index with the given item.
form.replaceListItem('fruits', 1, { name: 'Apple', available: true });

// Swaps two items of the list at the specified path.
// You should make sure that there are elements at the `from` and `to` index.
form.reorderListItem('fruits', { from: 1, to: 0 });
```

### Validation

[Form validation guide](https://mantine.dev/llms/form-validation.md)

```tsx
import { useForm } from '@mantine/form';

const form = useForm({
  mode: 'uncontrolled',
  initialValues: {
    email: '',
    user: {
      firstName: '',
      lastName: '',
    },
  },
  validate: {
    email: (value) => (value.length < 2 ? 'Invalid email' : null),
    user: {
      firstName: (value) =>
        value.length < 2
          ? 'First name must have at least 2 letters'
          : null,
    },
  },
});

// Validates all fields with the specified `validate` function or schema, sets form.errors
await form.validate();

// Validates a single field at the specified path, sets form.errors
await form.validateField('user.firstName');

// Works the same way as form.validate but does not set form.errors, returns Promise<boolean>
await form.isValid();
await form.isValid('user.firstName');

// true while any async validation is running
form.validating;

// true while async validation is running for a specific field
form.isValidating('email');
```

### Errors

[Form errors guide](https://mantine.dev/llms/form-errors.md)

Validation errors occur when defined validation rules were violated, `initialErrors` were specified in useForm properties,
or validation errors were set manually.

```tsx
// get the current errors state
form.errors;

// Set all errors
form.setErrors({ path: 'Error message', path2: 'Another error' });

// Set an error message at the specified path
form.setFieldError('user.lastName', 'No special characters allowed');

// Clears all errors
form.clearErrors();

// Clears the error of the field at the specified path
form.clearFieldError('path');
```

### onReset and onSubmit

Wrapper function for the form `onSubmit` and `onReset` event handler. The `onSubmit` handler accepts as a second argument a function
that will be called with the errors object when validation fails.

```tsx
import { useForm } from '@mantine/form';

function Demo() {
  const form = useForm({ mode: 'uncontrolled' });

  const handleSubmit = (values: typeof form.values) => {
    console.log(values);
  };

  return (
    <>
      {/* Supply handle submit as a single argument to receive validated values */}
      <form onSubmit={form.onSubmit(handleSubmit)} />

      {/* Supply a second argument to handle errors */}
      <form
        onSubmit={form.onSubmit(
          (values, event) => {
            console.log(
              values, // <- form.getValues() at the moment of submit
              event // <- form element submit event
            );
          },
          (validationErrors, values, event) => {
            console.log(
              validationErrors, // <- form.errors at the moment of submit
              values, // <- form.getValues() at the moment of submit
              event // <- form element submit event
            );
          }
        )}
      />

      {/* form.onReset calls form.reset */}
      <form onReset={form.onReset}></form>
    </>
  );
}
```

### onSubmitPreventDefault option

By default, `event.preventDefault()` is called on the form `onSubmit` handler.
If you want to change this behavior, you can pass the `onSubmitPreventDefault` option
to the `useForm` hook. It can have the following values:

* `always` (default) - always call `event.preventDefault()`
* `never` - never call `event.preventDefault()`
* `validation-failed` - call `event.preventDefault()` only if validation failed

```tsx
import { useForm } from '@mantine/form';

const form = useForm({
  mode: 'uncontrolled',
  onSubmitPreventDefault: 'never',
});
```

### Touched and dirty

[Touched & dirty guide](https://mantine.dev/llms/form-status.md)

```tsx
// Returns true if the user interacted with any field inside the form in any way
form.isTouched();

// Returns true if the user interacted with the field at the specified path
form.isTouched('path');

// Set all touched values
form.setTouched({ 'user.firstName': true, 'user.lastName': false });

// Clears the touched status of all fields
form.resetTouched();

// Returns true if form values are not deep equal to initialValues
form.isDirty();

// Returns true if the field value is not deep equal to initialValues
form.isDirty('path');

// Sets the dirty status of all fields
form.setDirty({ 'user.firstName': true, 'user.lastName': false });

// Clears the dirty status of all fields, saves form.values snapshot
// After form.resetDirty is called, form.isDirty will compare
// form.getValues() to the snapshot instead of initialValues
form.resetDirty();
```

## UseFormReturnType

`UseFormReturnType` can be used when you want to pass the `form` as a prop to another component:

```tsx
import { TextInput } from '@mantine/core';
import { useForm, UseFormReturnType } from '@mantine/form';

interface FormValues {
  name: string;
  occupation: string;
}

function NameInput({
  form,
}: {
  form: UseFormReturnType<FormValues>;
}) {
  return (
    <TextInput
      key={form.key('name')}
      {...form.getInputProps('name')}
    />
  );
}

function OccupationInput({
  form,
}: {
  form: UseFormReturnType<FormValues>;
}) {
  return (
    <TextInput
      key={form.key('occupation')}
      {...form.getInputProps('occupation')}
    />
  );
}

function Demo() {
  const form = useForm<FormValues>({
    mode: 'uncontrolled',
    initialValues: { name: '', occupation: '' },
  });
  return (
    <>
      <NameInput form={form} />
      <OccupationInput form={form} />
    </>
  );
}
```
