This project extends the mantine-next-template by integrating React Hook Form for form control and Zod for form validation. It provides a streamlined way to create and manage forms using Mantine UI components with React Hook Form.
Mantine's input components are seamlessly controlled using the custom <FormController />
as in here.
- Simplified form creation with a custom useForm hook
- Integration of Mantine UI components with React Hook Form
- Type-safe form validation using Zod
- Reduced boilerplate code for form setup
Our custom useForm
hook wraps the React Hook Form's useForm
to provide a more convenient API for creating forms with Mantine components. It simplifies the process of setting up controlled components and handling form submission.
Full example can be found here.
To use the useForm
hook, import it from the appropriate location in your project:
import { useForm, Form } from '../components/Form';
Then, create your form configuration:
const schema = z.object({
// Define your form schema here
});
type FormValues = z.infer<typeof schema>;
const form = useForm<FormValues>({
defaultValues: {
// Your form's initial values
},
onSubmit: async ({ data, methods }) => {
// Handle form submission
},
schema: schema, // Optional but recommended: Zod schema for validation
controllers: {
// Define your form fields here
},
});
Finally, use the form
object and the Form
component to render your form, noting that the Form
component must be wrapped around your form fields:
<Form form={form}>
{/* Your form fields are automatically rendered here based on the controllers */}
<Button type="submit" mt="md">
Submit
</Button>
</Form>
In some cases, you might want to separate the Form
and the submit Button
components. This can be useful for more complex layouts or when you need the button to be outside the form structure. To achieve this, you can use the useId()
hook from React, or any other method to generate a unique ID:
import { useId } from 'react';
function MyForm() {
const form = useForm({/* your form configuration */});
const formId = useId();
return (
<>
<Form form={form} id={formId} />
<Button type="submit" form={formId} mt="md">
Submit
</Button>
</>
);
}
-
defaultValues
: The initial values for your form fields. -
onSubmit
: Submission handler function. Receivesdata
,event
, andmethods
(of typeUseFormReturn
) as parameters. -
controllers
: Object defining the form fields and their properties. Each key in thecontrollers
object represents a form field.control
(required): The controlled component for the field (e.g., 'text-input', 'password-input').label
(required): The field's label.Field
(optional): A custom render function for additional flexibility (as described in the following section).options
(required inSelect
,MultiSelect
,CheckboxGroup
, etc.): For controllers that deal with options, an options prop is used instead of Mantine'sdata
prop. The options prop is an array of Option objects:
type Option = { label: ReactNode; value: any; }
- Original component props: All props supported by the original Mantine component.
schema
: Recommended. Zod schema for form validation.onSubmitError
: Error handler function for submission errors. Receiveserrors
,event
, andmethods
(of typeUseFormReturn
.) as parameters.
Grid Integration
: Each form field is wrapped in aGrid.Col
component, allowing you to easily create multi-column layouts and responsive forms. You can customize the grid behavior for each field using the col prop in the controller configuration.- Orientation for Group Controls: Checkbox groups, radio groups, and switch groups have an additional orientation prop that can be either 'horizontal' or 'vertical'. You can also provide orientationProps to further customize the layout.
- File Input Generics: The
FileInputProps
uses a generic<T extends boolean>
to determine whether it accepts multiple files or not.
The Field
property in the controllers object allows you to customize the rendering of individual form fields. This is particularly useful when you need to add additional components or modify the layout of a specific field.
const form = useForm<FormValues>({
// ... other properties
controllers: {
rememberMe: {
control: 'checkbox',
label: 'Remember me',
name: 'rememberMe',
Field: ({ fieldComponent }) => (
<Group position="apart">
{fieldComponent}
<Anchor<'a'> onClick={(event) => event.preventDefault()} href="#" size="sm">
Forgot password?
</Anchor>
</Group>
),
},
},
});
- Checkbox Group
- Checkbox
- File Input
- Multi-Select
- Number Input
- Password Input
- Radio Group
- Select
- Text Area
- Text Input
- Date Input
- Switch Group
- Pin Input
First, run the development server:
pnpm dev
# or
npm run dev
# or
yarn dev
Open http://localhost:3000 with your browser to see the result.
If you have any questions, please feel free to file issues or contact me at [email protected]
.