useModalForm
useModalForm
hook allows you to manage a form within a modal. It provides some useful methods to handle the form modal.
useModalForm
hook is extended from useForm
from the @pankod/refine-react-hook-form
package.
Usage
We'll show two examples, one for creating and one for editing a post. Let's see how useModalForm
is used in both.
Before we start, let's create a basic <Modal>
component.
type ModalPropsType = {
isOpen: boolean;
onClose: () => void;
};
export const Modal: React.FC<ModalPropsType> = ({
isOpen,
onClose,
children,
}) => {
if (!isOpen) return null;
return (
<>
<div className="overlay" onClick={onClose}></div>
<div className="modal">
<div className="modal-title">
<button className="close-button" onClick={onClose}>
×
</button>
</div>
<div className="modal-content">{children}</div>
</div>
</>
);
};
See styles
* {
box-sizing: border-box;
}
.overlay {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-color: rgba(0, 0, 0, 0.7);
z-index: 1000;
}
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
z-index: 1000;
width: 500px;
overflow-y: auto;
}
.modal .modal-title {
display: flex;
justify-content: flex-end;
padding: 4px;
}
.modal .modal-content {
padding: 0px 16px 16px 16px;
}
.form {
display: flex;
flex-direction: column;
gap: 8px;
}
.form .form-group {
display: flex;
flex-direction: column;
gap: 4px;
}
.form input,
select,
textarea {
width: 100%;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
}
Create Modal
We'll create a PostList
page that will display a list of posts. It will also display a <CreatePost>
modal that will allow us to create a new post. We'll use useModalForm
to manage the modal.
import { useTable } from "@pankod/refine-core";
import { useModalForm } from "@pankod/refine-react-hook-form";
import { CreatePost, EditPost } from "components";
export const PostList: React.FC = () => {
const { tableQueryResult } = useTable<IPost>({
initialSorter: [
{
field: "id",
order: "desc",
},
],
});
const createModalFormReturnValues = useModalForm({
refineCoreProps: { action: "create" },
});
const {
modal: { show: showCreateModal },
} = createModalFormReturnValues;
return (
<div>
<CreatePost {...createModalFormReturnValues} />
<button onClick={() => showCreateModal()}>Create Post</button>
<table>
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{tableQueryResult.data?.data.map((post) => (
<tr key={post.id}>
<td>{post.id}</td>
<td>{post.title}</td>
<td>{post.status}</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
interface IPost {
id: number;
title: string;
status: "published" | "draft" | "rejected";
}
<CreatePost>
component will be used to create a new post.
import { UseModalFormReturnType } from "@pankod/refine-react-hook-form";
import { Modal } from "../modal";
export const CreatePost: React.FC<UseModalFormReturnType> = ({
register,
formState: { errors },
refineCore: { onFinish, formLoading },
handleSubmit,
modal: { visible, close },
saveButtonProps,
}) => {
return (
<Modal isOpen={visible} onClose={close}>
<form className="form" onSubmit={handleSubmit(onFinish)}>
<div className="form-group">
<label>Title: </label>
<input
{...register("title", {
required: "This field is required",
})}
/>
{errors.title && <span>{errors.title.message}</span>}
</div>
<div className="form-group">
<label>Status: </label>
<select {...register("status")}>
<option value="published">published</option>
<option value="draft">draft</option>
<option value="rejected">rejected</option>
</select>
</div>
<div className="form-group">
<label>Content: </label>
<textarea
{...register("content", {
required: "This field is required",
})}
rows={10}
/>
{errors.content && <span>{errors.content.message}</span>}
</div>
<button type="submit" {...saveButtonProps}>
{formLoading ? "Loading" : "Save"}
</button>
</form>
</Modal>
);
};

Edit Modal
Now we'll create a <EditPost>
component that will allow us to edit a post within the modal. Also, we'll add a button to specify that wich post to edit.
import { useTable } from "@pankod/refine-core";
import { useModalForm } from "@pankod/refine-react-hook-form";
import { CreatePost, EditPost } from "components";
import { IPost } from "interfaces";
export const PostList: React.FC = () => {
const { tableQueryResult } = useTable<IPost>({
initialSorter: [
{
field: "id",
order: "desc",
},
],
});
const createModalFormReturnValues = useModalForm({
refineCoreProps: { action: "create" },
});
const editModalFormReturnValues = useModalForm({
refineCoreProps: { action: "edit" },
});
const {
modal: { show: showCreateModal },
} = createModalFormReturnValues;
const {
modal: { show: showEditModal },
} = editModalFormReturnValues;
return (
<div>
<CreatePost {...createModalFormReturnValues} />
<EditPost {...editModalFormReturnValues} />
<button onClick={() => showCreateModal()}>Create Post</button>
<table>
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Status</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{tableQueryResult.data?.data.map((post) => (
<tr key={post.id}>
<td>{post.id}</td>
<td>{post.title}</td>
<td>{post.status}</td>
<td>
<button onClick={() => showEditModal(post.id)}>
Edit
</button>
</td>
</tr>
))}
</tbody>
</table>
</div>
);
};
<EditPost>
component will be used to edit a post.
import { UseModalFormReturnType } from "@pankod/refine-react-hook-form";
import { Modal } from "components/modal";
export const EditPost: React.FC<UseModalFormReturnType> = ({
register,
formState: { errors },
refineCore: { onFinish, formLoading },
handleSubmit,
modal: { visible, close },
saveButtonProps,
}) => {
return (
<Modal isOpen={visible} onClose={close}>
<form className="form" onSubmit={handleSubmit(onFinish)}>
<div className="form-group">
<label>Title: </label>
<input
{...register("title", {
required: "This field is required",
})}
/>
{errors.title && <span>{errors.title.message}</span>}
</div>
<div className="form-group">
<label>Status: </label>
<select {...register("status")}>
<option value="published">published</option>
<option value="draft">draft</option>
<option value="rejected">rejected</option>
</select>
</div>
<div className="form-group">
<label>Content: </label>
<textarea
{...register("content", {
required: "This field is required",
})}
rows={10}
/>
{errors.content && <span>{errors.content.message}</span>}
</div>
<button type="submit" {...saveButtonProps}>
{formLoading ? "Loading" : "Save"}
</button>
</form>
</Modal>
);
};

API Reference
Properties
Property | Description | Type |
---|---|---|
modalProps | Configuration object for the modal | ModalPropsType |
refineCoreProps | Configuration object for the core of the useForm | UseFormProps |
React Hook Form Properties | See React Hook Form documentation |
ModalPropsType
Property Description Type Default defaultVisible Initial visibility state of the modal boolean
false
autoSubmitClose Whether the form should be submitted when the modal is closed boolean
true
autoResetForm Whether the form should be reset when the form is submitted boolean
true
Return values
Property | Description | Type |
---|---|---|
modal | Relevant states and methods to control the modal | ModalReturnValues |
refineCore | The return values of the useForm in the core | UseFormReturnValues |
React Hook Form Return Values | See React Hook Form documentation |
ModalReturnValues
Property Description Type visible State of modal visibility boolean
show Sets the visible state to true (id?: BaseKey) => void
close Sets the visible state to false () => void
submit Submits the form (values: TVariables) => void
title Modal title based on resource and action value string
saveButtonProps Props for a submit button { disabled: boolean, onClick: (e: React.BaseSyntheticEvent) => void; }