<Form>
The <Form>
component creates a <form>
to edit a record, and renders its children. It is a headless component used internally by <SimpleForm>
, <TabbedForm>
, and other form components.
<Form>
reads the record
from the RecordContext
, uses it to initialize the defaultValues of a react-hook-form via useForm
, turns the validate
function info a react-hook-form compatible form validator, notifies the user when the input validation fails, and creates a form context via <FormProvider>
.
Usage
Use <Form>
to build completely custom form layouts. Don’t forget to include a submit button:
import { Create, Form, TextInput, RichTextInput, SaveButton } from 'react-admin';
import { Grid } from '@mui/material';
export const PostCreate = () => (
<Create>
<Form>
<Grid container>
<Grid item xs={6}>
<TextInput source="title" fullWidth />
</Grid>
<Grid item xs={6}>
<TextInput source="author" fullWidth />
</Grid>
<Grid item xs={12}>
<RichTextInput source="body" fullWidth />
</Grid>
<Grid item xs={12}>
<SaveButton />
</Grid>
</Grid>
</Form>
</Create>
);
<Form>
calls react-hook-form’s useForm
hook, and places the result in a FormProvider
component. This means you can take advantage of the useFormContext
and useFormState
hooks to access the form state.
Here are all the props you can set on the <Form>
component:
Additional props are passed to the useForm
hook.
defaultValues
The value of the form defaultValues
prop is an object, or a function returning an object, specifying default values for the created record. For instance:
const postDefaultValue = () => ({ id: uuid(), created_at: new Date(), nb_views: 0 });
export const PostCreate = () => (
<Create>
<Form defaultValues={postDefaultValue}>
<Stack>
<TextInput source="title" />
<RichTextInput source="body" />
<NumberInput source="nb_views" />
<SaveButton />
</Stack>
</Form>
</Create>
);
Tip: You can include properties in the form defaultValues
that are not listed as input components, like the created_at
property in the previous example.
Tip: React-admin also allows to define default values at the input level. See the Setting default Values section.
id
Normally, a submit button only works when placed inside a <form>
tag. However, you can place a submit button outside of the form if the submit button form
matches the form id
.
Set this form id
via the id
prop.
export const PostCreate = () => (
<Create>
<Form defaultValues={postDefaultValue} id="post_create_form">
<Stack>
<TextInput source="title" />
<RichTextInput source="body" />
<NumberInput source="nb_views" />
</Stack>
</Form>
<SaveButton form="post_create_form" />
</Create>
);
noValidate
The <form novalidate>
attribute prevents the browser from validating the form. This is useful if you don’t want to use the browser’s default validation, or if you want to customize the error messages. To set this attribute on the underlying <form>
tag, set the noValidate
prop to true
.
const PostCreate = () => (
<Create>
<Form noValidate>
...
</Form>
</Create>
);
onSubmit
By default, the <Form>
calls the save
callback passed to it by the edit or create controller, via the SaveContext
. You can override this behavior by setting a callback as the onSubmit
prop manually.
export const PostCreate = () => {
const { id } = useParams();
const [create] = useCreate();
const postSave = (data) => {
create('posts', { id, data });
};
return (
<Create>
<Form onSubmit={postSave}>
...
</Form>
</Create>
);
};
validate
The value of the form validate
prop must be a function taking the record as input, and returning an object with error messages indexed by field. For instance:
const validateUserCreation = (values) => {
const errors = {};
if (!values.firstName) {
errors.firstName = 'The firstName is required';
}
if (!values.age) {
// You can return translation keys
errors.age = 'ra.validation.required';
} else if (values.age < 18) {
// Or an object if the translation messages need parameters
errors.age = {
message: 'ra.validation.minValue',
args: { min: 18 }
};
}
return errors
};
export const UserCreate = () => (
<Create>
<Form validate={validateUserCreation}>
<TextInput label="First Name" source="firstName" />
<TextInput label="Age" source="age" />
</Form>
</Create>
);
Tip: The validate
function can return a promise for asynchronous validation. See the Server-Side Validation section in the Validation documentation.
Tip: React-admin also allows to define validation rules at the input level. See the Validation chapter for details.
warnWhenUnsavedChanges
React-admin keeps track of the form state, so it can detect when the user leaves an Edit
or Create
page with unsaved changes. To avoid data loss, you can use this ability to ask the user to confirm before leaving a page with unsaved changes.
Warning about unsaved changes is an opt-in feature: you must set the warnWhenUnsavedChanges
prop in the form component to enable it:
export const TagEdit = () => (
<Edit>
<Form warnWhenUnsavedChanges>
...
</Form>
</Edit>
);