Set initial values with async request
import { useEffect } from 'react';import { useForm } from '@mantine/form';import { TextInput, Checkbox } from '@mantine/core';interface FormValues {email: string;terms: boolean;}function loadInitialValues(): Promise<FormValues> {return new Promise((resolve) => {setTimeout(() => resolve({ email: 'test@email', terms: true }), 2000);});}function Demo() {const form = useForm<FormValues>({ initialValues: { email: '', terms: false } });useEffect(() => {loadInitialValues().then((values) => {form.setValues(values);form.resetDirty(values);});}, []);return (<div style={{ maxWidth: 320, margin: 'auto' }}><TextInput label="Email" placeholder="Email" {...form.getInputProps('email')} /><Checkboxmt="sm"label="I accept terms and conditions"{...form.getInputProps('terms', { type: 'checkbox' })}/></div>);}
Save form values to local storage
import { useEffect } from 'react';import { useForm } from '@mantine/form';import { TextInput } from '@mantine/core';function Demo() {const form = useForm({ initialValues: { name: '', occupation: '' } });useEffect(() => {const storedValue = window.localStorage.getItem('user-form');if (storedValue) {try {form.setValues(JSON.parse(window.localStorage.getItem('user-form')));} catch (e) {console.log('Failed to parse stored value');}}}, []);useEffect(() => {window.localStorage.setItem('user-form', JSON.stringify(form.values));}, [form.values]);return (<div style={{ maxWidth: 320, margin: 'auto' }}><TextInput label="Name" placeholder="Name" {...form.getInputProps('name')} /><TextInputmt="md"label="Occupation"placeholder="Occupation"{...form.getInputProps('occupation')}/></div>);}
List items reordering
Form values:
{ "employees": [ { "name": "John Doe", "email": "john@mantine.dev" }, { "name": "Bill Love", "email": "bill@mantine.dev" }, { "name": "Nancy Eagle", "email": "nanacy@mantine.dev" }, { "name": "Lim Notch", "email": "lim@mantine.dev" }, { "name": "Susan Seven", "email": "susan@mantine.dev" } ] }
import { Group, TextInput, Box, Text, Code, Button, Center } from '@mantine/core';import { useForm } from '@mantine/form';import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd';import { IconGripVertical } from '@tabler/icons';function Demo() {const form = useForm({initialValues: {employees: [{ name: 'John Doe', email: 'john@mantine.dev' },{ name: 'Bill Love', email: 'bill@mantine.dev' },{ name: 'Nancy Eagle', email: 'nanacy@mantine.dev' },{ name: 'Lim Notch', email: 'lim@mantine.dev' },{ name: 'Susan Seven', email: 'susan@mantine.dev' },],},});const fields = form.values.employees.map((_, index) => (<Draggable key={index} index={index} draggableId={index.toString()}>{(provided) => (<Group ref={provided.innerRef} mt="xs" {...provided.draggableProps}><Center {...provided.dragHandleProps}><IconGripVertical size={18} /></Center><TextInput placeholder="John Doe" {...form.getInputProps(`employees.${index}.name`)} /><TextInputplaceholder="example@mail.com"{...form.getInputProps(`employees.${index}.email`)}/></Group>)}</Draggable>));return (<Box sx={{ maxWidth: 500 }} mx="auto"><DragDropContextonDragEnd={({ destination, source }) =>form.reorderListItem('employees', { from: source.index, to: destination.index })}><Droppable droppableId="dnd-list" direction="vertical">{(provided) => (<div {...provided.droppableProps} ref={provided.innerRef}>{fields}{provided.placeholder}</div>)}</Droppable></DragDropContext><Group position="center" mt="md"><Button onClick={() => form.insertListItem('employees', { name: '', email: '' })}>Add employee</Button></Group><Text size="sm" weight={500} mt="md">Form values:</Text><Code block>{JSON.stringify(form.values, null, 2)}</Code></Box>);}
Form with multiple steps
import { useState } from 'react';import { Stepper, Button, Group, TextInput, PasswordInput, Code } from '@mantine/core';import { useForm } from '@mantine/form';function Demo() {const [active, setActive] = useState(0);const form = useForm({initialValues: {username: '',password: '',name: '',email: '',website: '',github: '',},validate: (values) => {if (active === 0) {return {username:values.username.trim().length < 6? 'Username must include at least 6 characters': null,password:values.password.length < 6 ? 'Password must include at least 6 characters' : null,};}if (active === 1) {return {name: values.name.trim().length < 2 ? 'Name must include at least 2 characters' : null,email: /^\S+@\S+$/.test(values.email) ? null : 'Invalid email',};}return {};},});const nextStep = () =>setActive((current) => {if (form.validate().hasErrors) {return current;}return current < 3 ? current + 1 : current;});const prevStep = () => setActive((current) => (current > 0 ? current - 1 : current));return (<><Stepper active={active} breakpoint="sm"><Stepper.Step label="First step" description="Profile settings"><TextInput label="Username" placeholder="Username" {...form.getInputProps('username')} /><PasswordInputmt="md"label="Password"placeholder="Password"{...form.getInputProps('password')}/></Stepper.Step><Stepper.Step label="Second step" description="Personal information"><TextInput label="Name" placeholder="Name" {...form.getInputProps('name')} /><TextInput mt="md" label="Email" placeholder="Email" {...form.getInputProps('email')} /></Stepper.Step><Stepper.Step label="Final step" description="Social media"><TextInput label="Website" placeholder="Website" {...form.getInputProps('website')} /><TextInputmt="md"label="GitHub"placeholder="GitHub"{...form.getInputProps('github')}/></Stepper.Step><Stepper.Completed>Completed! Form values:<Code block mt="xl">{JSON.stringify(form.values, null, 2)}</Code></Stepper.Completed></Stepper><Group position="right" mt="xl">{active !== 0 && (<Button variant="default" onClick={prevStep}>Back</Button>)}{active !== 3 && <Button onClick={nextStep}>Next step</Button>}</Group></>);}