Created
February 21, 2024 02:22
-
-
Save MrNekoShin/0f5204764bee15e32fc6c51001a63ab6 to your computer and use it in GitHub Desktop.
Dynamic React Hook Form From Schema
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React, { ChangeEvent } from "react"; | |
import { FieldError, FieldErrorsImpl, Merge, useForm } from "react-hook-form"; | |
type ValidationSchema = { | |
required?: | |
| string | |
| { | |
value: boolean; | |
message: string; | |
}; | |
maxLength?: { | |
value: number; | |
message: string; | |
}; | |
minLength?: { | |
value: number; | |
message: string; | |
}; | |
max?: { | |
value: number; | |
message: string; | |
}; | |
min?: { | |
value: number; | |
message: string; | |
}; | |
pattern?: { | |
value: RegExp; | |
message: string; | |
}; | |
// validate?: Function | Object; | |
}; | |
type SchemaField = { | |
label: string; | |
type: string; | |
validation: ValidationSchema; | |
}; | |
type Schema = { | |
[key: string]: SchemaField; | |
}; | |
type Data = { | |
[key: string]: string; | |
}; | |
const DynamicForm = ({ schema }: { schema: Schema }) => { | |
const { | |
register, | |
handleSubmit, | |
formState: { errors }, | |
setValue, | |
} = useForm(); | |
const onSubmit = (data: Data) => { | |
console.log(data); | |
}; | |
const handleInputChange = ( | |
event: ChangeEvent<HTMLInputElement | HTMLSelectElement>, | |
) => { | |
const { name, value } = event.target; | |
setValue(name, value); | |
}; | |
const renderContent = ( | |
content: | |
| string | |
| FieldError | |
| Merge<FieldError, FieldErrorsImpl<any>> | |
| undefined, | |
): React.ReactNode => { | |
if (typeof content === "string") { | |
return content; // String can be directly assigned to ReactNode | |
} else if (typeof content === "object" && "message" in content) { | |
return (content as FieldError).message; // Rendering the error message | |
} else { | |
return null; // Undefined or other types, handle accordingly | |
} | |
}; | |
const renderFormControl = (key: string, field: SchemaField) => { | |
switch (field.type) { | |
case "text": | |
case "email": | |
case "number": | |
case "password": | |
return ( | |
<div key={key}> | |
<label>{field.label}</label> | |
<input | |
{...register(key, field.validation)} | |
onChange={handleInputChange} | |
/> | |
{errors[key] && <span>{renderContent(errors[key])}</span>} | |
</div> | |
); | |
case "select": | |
return ( | |
<div key={key}> | |
<label>{field.label}</label> | |
<select | |
{...register(key, field.validation)} | |
onChange={handleInputChange} | |
> | |
{/* Options for select dropdown */} | |
</select> | |
{errors[key] && <span>{renderContent(errors[key])}</span>} | |
</div> | |
); | |
case "checkbox": | |
return ( | |
<div key={key}> | |
<label> | |
<input | |
type="checkbox" | |
{...register(key, field.validation)} | |
onChange={handleInputChange} | |
/> | |
{field.label} | |
</label> | |
{errors[key] && <span>{renderContent(errors[key])}</span>} | |
</div> | |
); | |
default: | |
return null; | |
} | |
}; | |
return ( | |
<form onSubmit={handleSubmit(onSubmit)}> | |
{/* Render form controls dynamically */} | |
{Object.entries(schema).map(([key, field]) => | |
renderFormControl(key, field), | |
)} | |
<button type="submit">Submit</button> | |
</form> | |
); | |
}; | |
export default DynamicForm; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const schema = { | |
firstName: { | |
label: "First Name", | |
type: "text", | |
validation: { | |
required: "First Name is required", | |
minLength: { | |
value: 3, | |
message: "First Name should have at least 3 characters", | |
}, | |
}, | |
}, | |
lastName: { | |
label: "Last Name", | |
type: "text", | |
validation: { | |
required: "Last Name is required", | |
}, | |
}, | |
email: { | |
label: "Email", | |
type: "email", | |
validation: { | |
required: "Email is required", | |
pattern: { | |
value: /^\S+@\S+$/i, | |
message: "Invalid email address", | |
}, | |
}, | |
}, | |
}; | |
export default schema; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment