20 January 2025
Formity: The Ultimate Tool For Multi-Step Forms In React
As a frontend developer, you've likely faced the challenge of creating multi-step forms. These forms can be tricky to build, especially when they must adapt dynamically to user responses. Formity is designed to simplify this process, filling the gap left by existing form libraries.
The Problem With Existing Form Libraries
There are many great form libraries available, such as React Hook Form, Formik, and Tanstack Form, which excel at handling single-step forms efficiently. However, these form libraries lack built-in solutions for managing multi-step navigation and advanced logic. For instance, building an onboarding process or an interactive survey can be quite challenging with these tools.
This is where Formity steps in - a library to address the complexities of multi-step forms, offering developers the tools they need to create forms that are both dynamic and scalable.
Key Features of Formity
Formity provides a range of features that make it the go-to tool for creating advanced forms.
Advanced Logic
You can add sophisticated logic to your multi-step forms using features such as conditions, loops, and variables. This enables you to create truly dynamic forms where the flow adapts to user input.
Integration With Any Form Library
Formity doesn't force you to abandon your favorite form library. You can seamlessly integrate it with libraries like React Hook Form, Formik, or any other form-handling tool.
Advanced Type Inference
For TypeScript users, Formity offers advanced type inference to make the developer experience smooth and error-free. You'll get better autocomplete and improved type safety.
How It Works
Formity's simplicity lies in its intuitive API. To create a multi-step form, you only need to:
Use the
Formity
component.Create a schema that specifies the structure and behavior of the form.
Formity component
The Formity
component is used to render the multi-step form.
import { useCallback, useState } from "react";
import { Formity, OnReturn, ReturnValues } from "@formity/react";
import { Data } from "@/components";
import { schema, Values } from "./schema";
export default function App() {
const [values, setValues] = useState<ReturnValues<Values> | null>(null);
const onReturn = useCallback<OnReturn<Values>>((values) => {
setValues(values);
}, []);
if (values) {
return <Data data={values} onStart={() => setValues(null)} />;
}
return <Formity<Values> schema={schema} onReturn={onReturn} />;
}
Form schema
The form schema is what defines the structure and behavior of the form.
export type Values = [
// ...
];
export const schema: Schema<Values> = [
{
form: {
values: () => ({
working: [true, []],
}),
render: ({ values, ...rest }) => (
<Controller step="working" {...rest}>
<FormView
defaultValues={values}
resolver={zodResolver(
z.object({
working: z.boolean(),
}),
)}
>
<FormLayout
heading="Are you currently working?"
description="We would like to know if you are working for a company"
fields={[<YesNo key="working" name="working" label="Working" />]}
button={<Next>Next</Next>}
/>
</FormView>
</Controller>
),
},
},
{
cond: {
if: ({ working }) => working,
then: [
{
form: {
values: () => ({
company: ["", []],
}),
render: ({ values, ...rest }) => (
<Controller step="company" {...rest}>
<FormView
defaultValues={values}
resolver={zodResolver(
z.object({
company: z.string(),
}),
)}
>
<FormLayout
heading="At what company?"
description="We would like to know the name of the company"
fields={[
<TextField
key="company"
name="company"
label="Company"
/>,
]}
button={<Next>Next</Next>}
back={<Back />}
/>
</FormView>
</Controller>
),
},
},
{
return: ({ working, company }) => ({
working,
company,
}),
},
],
else: [
{
form: {
values: () => ({
searching: [false, []],
}),
render: ({ values, ...rest }) => (
<Controller step="searching" {...rest}>
<FormView
defaultValues={values}
resolver={zodResolver(
z.object({
searching: z.boolean(),
}),
)}
>
<FormLayout
heading="Are you looking for a job?"
description="If you are looking for a job, we would like to know"
fields={[
<YesNo
key="searching"
name="searching"
label="Searching"
/>,
]}
button={<Next>Next</Next>}
back={<Back />}
/>
</FormView>
</Controller>
),
},
},
{
return: ({ working, searching }) => ({
working,
searching,
}),
},
],
},
},
];
Real-World Use Cases
Formity provides the flexibility to create applications that require dynamic, adaptive logic, making it ideal for handling complex workflows. Below we provide two practical examples.
Example #1: Quiz application
A quiz application that asks the user several questions and returns the number of correct answers.
Example #2: Fitness application
A fitness application that gives you workout routines based on your preferences and fitness goals.
Why Choose Formity?
Formity excels at solving the complex challenges of multi-step forms. It provides developers with a powerful toolkit to design scalable, dynamic, and logic-driven solutions for a wide range of use cases, ensuring flexibility and ease of use.
So next time you're tasked with creating a multi-step form, give Formity a try. With its advanced logic capabilities, compatibility with popular form libraries, and robust TypeScript support, it empowers frontend developers to build dynamic and adaptive forms effortlessly.