Skip to main content
Version: 3.xx.xx

useStepsForm

useStepsForm hook allows you to split your form under an Ant Design based Steps component and provides you with a few useful functionalities that will help you manage your form.

import { useStepsForm } from "@pankod/refine-antd";

const { stepsProps, formProps } = useStepsForm<IPost>();

All we have to do is to pass the props it returns to our <Steps> and <Form> components.

Usage

We'll do two examples, one for creating and one for editing a post. Let's see how useStepsForm is used in both.

Create

For the sake of simplicity, in this example we're going to build a Post create form that consists of only a title and a relational category field.

To split your form items under a <Steps> component, first import and use useStepsForm hook in your page:

pages/posts/create.tsx
import { useStepsForm } from "@pankod/refine-antd";

export const PostCreate: React.FC = () => {
const {
current,
gotoStep,
stepsProps,
formProps,
saveButtonProps,
queryResult,
} = useStepsForm<IPost>();

return null;
};

interface ICategory {
id: number;
title: string;
}

interface IPost {
id: number;
title: string;
status: "published" | "draft" | "rejected";
}

useStepsForm is generic over the type form data to help you type check your code.

This hook returns a set of useful values to render steps form. Given current value, you should have a way to render your form items conditionally with this index value. You can use an array to achieve this.

Here, each item of formList corresponds to one step in form:

pages/posts/create.tsx
import { useStepsForm, useSelect, Form, Input, Select } from "@pankod/refine-antd";

export const PostCreate: React.FC = () => {
const {
current,
gotoStep,
stepsProps,
formProps,
saveButtonProps,
} = useStepsForm<IPost>();

const { selectProps: categorySelectProps } = useSelect<ICategory>({
resource: "categories",
});

const formList = [
<>
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
</>,
<>
<Form.Item
label="Category"
name={["category", "id"]}
rules={[
{
required: true,
},
]}
>
<Select {...categorySelectProps} />
</Form.Item>
</>,
];

return null;
};
tip

Since category is a relational data, we use useSelect to fetch its data.

Refer to useSelect documentation for detailed usage.


You should use stepsProps on <Steps> component, formProps on the <Form> component respectively. And as the last step, you should render the <Steps> component besides the form like this:

pages/posts/create.tsx
import {
useStepsForm,
useSelect,
Form,
Input,
Select,
Create,
Steps,
} from "@pankod/refine-antd";

export const PostCreate: React.FC = () => {
const {
current,
gotoStep,
stepsProps,
formProps,
saveButtonProps,
queryResult,
} = useStepsForm<IPost>();

const { selectProps: categorySelectProps } = useSelect<ICategory>({
resource: "categories",
});

const formList = [
<>
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
</>,
<>
<Form.Item
label="Category"
name={["category", "id"]}
rules={[
{
required: true,
},
]}
>
<Select {...categorySelectProps} />
</Form.Item>
</>,
];

return (
<Create saveButtonProps={saveButtonProps}>
<Steps {...stepsProps}>
<Steps.Step title="First Step" />
<Steps.Step title="Second Step" />
</Steps>
<Form {...formProps} layout="vertical">
{formList[current]}
</Form>
</Create>
);
};
Important

Make sure to add as much <Steps.Step> components as the number of steps in the formList array.


To help users navigate between steps in the form, you can use action buttons. Your navigation buttons should use the gotoStep function that was previously returned from the the useStepsForm hook.

pages/posts/create.tsx
import {
useStepsForm,
useSelect,
Form,
Input,
Select,
Create,
Steps,
Button,
SaveButton,
} from "@pankod/refine-antd";

export const PostCreate: React.FC = () => {
const {
current,
gotoStep,
stepsProps,
formProps,
saveButtonProps,
queryResult,
submit,
} = useStepsForm<IPost>();

const { selectProps: categorySelectProps } = useSelect<ICategory>({
resource: "categories",
});

const formList = [
<>
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
</>,
<>
<Form.Item
label="Category"
name={["category", "id"]}
rules={[
{
required: true,
},
]}
>
<Select {...categorySelectProps} />
</Form.Item>
</>,
];

return (
<Create
actionButtons={
<>
{current > 0 && (
<Button
onClick={() => {
gotoStep(current - 1);
}}
>
Previous
</Button>
)}
{current < formList.length - 1 && (
<Button
onClick={() => {
gotoStep(current + 1);
}}
>
Next
</Button>
)}
{current === formList.length - 1 && (
<SaveButton
{...saveButtonProps}
style={{ marginRight: 10 }}
onClick={() => submit()}
/>
)}
</>
}
>
<Steps {...stepsProps}>
<Steps.Step title="First Step" />
<Steps.Step title="Second Step" />
</Steps>
<Form {...formProps} layout="vertical">
{formList[current]}
</Form>
</Create>
);
};
Steps form example

Edit

In this example, we'll just look at what's different from the example above.

pages/posts/edit.tsx
import {
useStepsForm,
useSelect,
Form,
Input,
Select,
Steps,
Button,
SaveButton,
Edit,
} from "@pankod/refine-antd";

export const PostCreate: React.FC = () => {
const {
current,
gotoStep,
stepsProps,
formProps,
saveButtonProps,
queryResult,
submit,
} = useStepsForm<IPost>();

const postData = queryResult?.data?.data;
const { selectProps: categorySelectProps } = useSelect<ICategory>({
resource: "categories",
defaultValue: postData?.category.id,
});

const formList = [
<>
<Form.Item
label="Title"
name="title"
rules={[
{
required: true,
},
]}
>
<Input />
</Form.Item>
</>,
<>
<Form.Item
label="Category"
name={["category", "id"]}
rules={[
{
required: true,
},
]}
>
<Select {...categorySelectProps} />
</Form.Item>
</>,
];

return (
<Edit
actionButtons={
<>
{current > 0 && (
<Button
onClick={() => {
gotoStep(current - 1);
}}
>
Previous
</Button>
)}
{current < formList.length - 1 && (
<Button
onClick={() => {
gotoStep(current + 1);
}}
>
Next
</Button>
)}
{current === formList.length - 1 && (
<SaveButton
{...saveButtonProps}
style={{ marginRight: 10 }}
onClick={() => submit()}
/>
)}
</>
}
>
<Steps {...stepsProps}>
<Steps.Step title="First Step" />
<Steps.Step title="Second Step" />
</Steps>
<Form {...formProps} layout="vertical">
{formList[current]}
</Form>
</Edit>
);
};

API Reference

Properties

*: These props have default values in RefineContext and can also be set on <Refine> component. useModalForm will use what is passed to <Refine> as default but a local value will override it.

**: If not explicitly configured, default value of redirect depends on which action used. If action is create, redirects default value is edit (created resources edit page). if action is edit instead, redirects default value is list.

Return Values

KeyDescriptionType
stepsPropsAnt Design steps propsStepsProps
currentCurrent step, counting from 0.number
gotoStepGo to the target step(step: number) => void
formPropsAnt Design form propsFormProps
formAnt Design form instanceFormInstance<TVariables>
formLoadingLoading status of formboolean
defaultFormValuesLoadingDefaultFormValues loading status of formboolean
submitSubmit method, the parameter is the value of the form fields() => void
saveButtonPropsProps for a submit button{ disabled: boolean; onClick: () => void; loading: boolean; }
queryResultResult of the query of a recordQueryObserverResult<{ data: TData }>
mutationResultResult of the mutation triggered by submitting the formUseMutationResult<
{ data: TData },
TError,
{ resource: string; values: TVariables; },
unknown>](https://react-query.tanstack.com/reference/useMutation)
idRecord id for clone and create actionBaseKey
setIdid setterDispatch<SetStateAction< string | number | undefined>>

Type Parameters

PropertyDesriptionDefault
TDataResult data of the query that extends BaseRecordBaseRecord
TErrorCustom error object that extends HttpErrorHttpError
TVariablesValues for params.{}

Live StackBlitz Example