Skip to main content
🧙‍♂️ refine grants your wishes! Please give us a ⭐️ on GitHub to keep the magic going.
Version: 4.xx.xx

Custom Form Validation

In refine, we can use the form validation that comes with Ant Design with the rules property of the Form.Item component.

<Form>
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
{
min: 5,
},
]}
>
<Input />
</Form.Item>
...
</Form>

In addition to pre-defined rules, we can also prepare custom rules with the validator function.

Example

Now let's prepare a rule that checks if the titles of the posts are unique. We have an endpoint like the below. We will do the uniqueness check here.

https://api.fake-rest.refine.dev/posts-unique-check?title=Example
{
"isAvailable": true
}
localhost:3000/posts/create
import { useForm, Create, CreateButton } from "@refinedev/antd";
import { Form, Input } from "antd";
import { useApiUrl, useCustom, HttpError } from "@refinedev/core";

interface IPost {
title: string;
}

interface PostUniqueCheckResponse {
isAvailable: boolean;
}

interface PostUniqueCheckRequestQuery {
title: string;
}

const PostCreate: React.FC = () => {
const { formProps, saveButtonProps } = useForm<IPost>();

const [title, setTitle] = useState("");

const apiUrl = useApiUrl();
const url = `${apiUrl}/posts-unique-check`;
const { refetch } = useCustom<
PostUniqueCheckResponse,
HttpError,
PostUniqueCheckRequestQuery
>({
url,
method: "get",
config: {
query: {
title,
},
},
queryOptions: {
enabled: false,
},
});

return (
<Create saveButtonProps={saveButtonProps}>
<Form {...formProps} layout="vertical">
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
{
validator: async (_, value) => {
if (!value) return;
const { data } = await refetch();
if (data && data.data.isAvailable) {
return Promise.resolve();
}
return Promise.reject(
new Error("'title' must be unique"),
);
},
},
]}
>
<Input
defaultValue="Test"
onChange={(event) => setTitle(event.target.value)}
/>
</Form.Item>
</Form>
</Create>
);
};
important

Value must be kept in the state.

<Input onChange={(event) => setTitle(event.target.value)} />