Back to Mantine

Use Form

apps/mantine.dev/src/pages/form/use-form.mdx

9.2.07.5 KB
Original Source

import { FormDemos } from '@docs/demos'; import { Layout } from '@/layout'; import { MDX_DATA } from '@/mdx';

export default Layout(MDX_DATA.useForm);

Installation

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

<InstallScript packages="@mantine/form" />

Usage

<Demo data={FormDemos.usage} />

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

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

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

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

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 (
    <>
      <form onSubmit={form.onSubmit(handleSubmit)} />
      <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={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

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} />
    </>
  );
}