Salut,
Table of content
- Introduction
- Dynamic Form Data
- React Hook Form
- Text Input Field
- Text Area Field
- Radio Field
- Dropdown Field
- Checkbox Field
- Error Component
- Complete Input Component
Introduction
API-driven forms refer to the practice of using APIs (Application Programming Interfaces) to integrate and manage forms within web applications. This approach offers several benefits that can enhance the functionality and user experience of forms on websites or applications.
- Dynamic Data Loading
- Real-time Validation
- Flexibility and Customization
- Secure Data Handling
- Seamless Integration with Backends
- Consistency Across Platforms
- Reduced Development Time
- Scalability
- Easier Updates and Maintenance
Prerequisite - React Hook Form. As this article is related to API-driven forms, that's why I'll now elaborate on the working of React Hook Form. However, if you need an understanding of this library, just leave a comment and I'll explain it in another article.
Dynamic Form Data
When we call an API for form fields, it should have the following payload. I am going to write my code accordingly to this payload if you guys want a different payload. You will be required to make changes in the code accordingly. I am not calling any API in this article, just creating a variable "dynamicForm" and assigning payload to it.
const dynamicForm = {
firstName: {
label: "First Name",
type: "text",
placeholder: "",
defaultValue: "Yes",
rules: {
required: true,
},
},
lastName: {
label: "Last Name",
type: "text",
placeholder: "",
defaultValue: "",
rules: {
required: true,
},
},
email: {
label: "Email",
type: "email",
placeholder: "",
defaultValue: "",
rules: {
required: true,
},
},
subject: {
label: "Subject",
type: "dropdown",
options: ["Chemistry", "Physics", "Arts"],
defaultValue: "",
rules: {
required: true,
},
},
message: {
label: "Message",
type: "textarea",
placeholder: "",
defaultValue: "",
rules: {
required: false,
},
},
}
React Hook Form
I will make a component named "Input" but for now let's suppose there is a component. Now, let's call the form and this Input component.
const {
handleSubmit,
control,
formState: { errors },
} = useForm();
Let's convert dynamicForm object to array and map through it the Input component.
const formInputs = Object.keys(dynamicForm).map((e, i) => {
const { rules, defaultValue, label } = dynamicForm[e];
return (
<section key={i}>
<label className="grey">
{label} {rules?.required ? <span className="red">*</span> : ""}
</label>
<Controller
name={e}
control={control}
rules={rules}
defaultValue={defaultValue}
render={({ field }) => (
<div>
<Input
cClass="input-1"
value={field.value}
onChange={field.onChange}
{...dynamicForm[e]}
/>
</div>
)}
/>
{errors[e] && <Error>This field is required</Error>}
</section>
);
});
Now, add a submit handler and form to our main component.
const onSubmit = (data) => console.log(data);
return (
<div className="wrapper">
<form onSubmit={handleSubmit(onSubmit)}>
{formInputs}
<div>
<button type="submit" className="btn-1">
Submit
</button>
</div>
</form>
</div>
);
Text Input Field
const Input = ({ cClass, value, onChange, type, ...rest }) => {
return (
<input
type='text'
placeholder={rest?.placeholder}
onChange={(e) => onChange(e.target.value)}
value={value}
className={cClass}
/>
);
}
Text Area Field
const Input = ({ cClass, value, onChange, type, ...rest }) => {
return (
<textarea name="" id="" cols="30" rows="10" className={cClass} onChange={(e) => onChange(e.target.value)}>{value}</textarea>
);
}
Radio Field
const Input = ({ cClass, value, onChange, type, ...rest }) => {
return rest?.options.map((i) => (
<label>
<input
type='radio'
key={i}
value={i}
onChange={(e) => onChange(e.target.value)}
checked={value === i}
/>
{i}
</label>
));
}
Dropdown Field
const Input = ({ cClass, value, onChange, type, ...rest }) => {
return (
<select value={value} onChange={(e) => onChange(e.target.value)} className={cClass}>
<option value="">Select an option</option>
{rest?.options.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
);
}
CheckBox Field
const Input = ({ cClass, value, onChange, type, ...rest }) => {
return (
<label>
<input
type="checkbox"
onChange={(e) => onChange(e.target.checked)}
checked={value}
/>
{rest?.checkboxLabel}
</label>
);
}
I used a switch statement to check the type.
Error Component
export const Error = ({ children }) => <p style={{ color: "red" }}>{children}</p>;
Complete Input Component
const Input = ({ cClass, value, onChange, type, ...rest }) => {
switch (type) {
case "text":
return (
<input
type='text'
placeholder={rest?.placeholder}
onChange={(e) => onChange(e.target.value)}
value={value}
className={cClass}
/>
);
case "email":
return (
<input
type='email'
placeholder={rest?.placeholder}
onChange={(e) => onChange(e.target.value)}
value={value}
className={cClass}
/>
);
case "textarea":
return (
<textarea name="" id="" cols="30" rows="10" className={cClass} onChange={(e) => onChange(e.target.value)}>{value}</textarea>
);
case "radio":
return rest?.options.map((i) => (
<label>
<input
type='radio'
key={i}
value={i}
onChange={(e) => onChange(e.target.value)}
checked={value === i}
/>
{i}
</label>
));
case "dropdown":
return (
<select value={value} onChange={(e) => onChange(e.target.value)} className={cClass}>
<option value="">Select an option</option>
{rest?.options.map((option) => (
<option key={option} value={option}>
{option}
</option>
))}
</select>
);
case "checkbox":
return (
<label>
<input
type="checkbox"
onChange={(e) => onChange(e.target.checked)}
checked={value}
/>
{rest?.checkboxLabel}
</label>
);
default:
return null;
}
};
export default Input
Frontend would render like this.
Thank you for reading this far. This is a brief introduction of API Driven forms
If you find this article useful, please like ❤ and share this article. Someone could find it useful too. If you find anything technically inaccurate please feel free to leave a comment.
Hope it's a nice and informative read for you. Follow me on LinkedIn for more helpful resources or reach out for any mutual opportunity.
Few more articles:
Top comments (0)