npm i formua
- validateForm method added to formua result object
- validatedErrors added to formua result object
function Formua(params: FormuaParams /*OPTIONAL*/ ): FormuaResult;
type FormuaParams = {
form: HTMLFormElement, // OPTIONAL: Specifies form element explicitly
validations: ValidationMap, // OPTIONAL: Validations per input name
transforms: TransformationMap, // OPTIONAL: Transformations per input name
legacyListeners: boolean // OPTIONAL: Try enabling this if you face compatibility issues
}
type FormuaResult = {
formData: FormData, // Returns transformations applied form data
pureData: FormData, // Returns pure form data
formErrors: Record<string, string>, // Returns error messages for each invalid input field
isFormValid: boolean // Returns true if all fields are valid otherwise false,
validateForm: () => ValidationResult
validatedErrors: Record<string, string> // If validateForm method is called once then returns error messages for each invalid input field otherwise returns errors messages for only fields those triggered blur event
}
// FormData is completely immutable
type FormData = {
data: Record<string, any>; // same as getAll()
get(key): any;
getAll(): Record<string, any>;
has(key): boolean;
set(key, value): FormData; // returns a new form data with updated key:value, also can be used as append method
select(...keys: string[]): Record<string, any>; // returns a new form data with only selected fields
drop(...keys: string[]): Record<string, any>; // returns a new form data without specified fields
keys(): string[];
values(): any[];
entries(): Record<string, any>;
toString(): string;
toJSON(): Record<string, any>;
}
type ValidationMap = {
[fieldName: string]: Validation
}
type Validation = {
errorMessage: string,
validator: (o: any) => boolean
}
type ValidationResult = {
isValid: boolean,
errors: Record<string, string>
}
type TransformationMap = {
[fieldName: string]: TransformerFunction
}
interface TransformerFunction{
(o: any) => any
}
If you have only single form in the page, formua will automatically detect it and retrieve data from it. A Typescript example is provided below.
import { Formua } from "formua";
import { chainAnd, hasNoSpecialCharacters, isEmail, minLength, required } from "formua/helpers";
export default function SignupForm() {
const { formData, pureData, formErrors, isFormValid } = Formua({
validations: {
username: {
errorMessage: "Username is required and must contain no special characters",
validator: chainAnd(required, hasNoSpecialCharacters)
},
email: {
errorMessage: "Please enter your email address",
validator: isEmail
},
password: {
validator: minLength(8),
errorMessage: "Password must be at least 8 characters long"
}
}
});
return (
<form>
<input name="username" placeholder="Username" />
{formErrors.username && ( <div className="error">{formErrors.username}</div> )}
<input name="email" placeholder="Email" />
{formErrors.email && ( <div className="error">{formErrors.email}</div> )}
<input type="password" name="password" placeholder="Password" />
{formErrors["password"] && ( <div className="error">{formErrors["password"]}</div> )}
<button disabled={!isFormValid}>Sign Up</button>
</form>
);
}
The example below shows how to use Formua to validate, transform and post a form data without any statefull input element. Typescript definitions are optional.
import axios from "axios";
import { Formua, FormData } from "formua";
import { chainAnd, hasNoSpecialCharacters, isEmail, minLength, minTrimmedLength, sameAs, trim, sameAsField } from "formua/helpers";
import { useEffect, useRef } from "react";
export default function SignupForm() {
const formRef = useRef<HTMLFormElement>(null);
const { formData, pureData, formErrors, isFormValid } = Formua({
form: formRef.current,
validations: {
username: {
errorMessage: "Username must be at least 4 characters long and must contain no special characters",
validator: chainAnd(minTrimmedLength(4), hasNoSpecialCharacters)
},
email: {
errorMessage: "Please enter your email address",
validator: isEmail
},
"email-again": {
errorMessage: "Emails do not match",
validator: sameAsField("email")
},
password: {
validator: minLength(8),
errorMessage: "Password must be at least 8 characters long"
},
"password-again": {
errorMessage: "Passwords do not match",
validator: sameAsField("password")
}
},
transforms: {
username: trim
}
});
function submitHandler() {
axios.post("/signup", formData.getAll())
.then(res => console.log("success!"))
.catch(err => console.log("error!"));
}
return (
<form ref={formRef} onSubmit={submitHandler}>
<input name="username" placeholder="Username" />
{formErrors.username && (<div className="error">{formErrors.username}</div>)}
<input name="email" placeholder="Email" />
{formErrors.email && (<div className="error">{formErrors.email}</div>)}
<input name="email-again" placeholder="Email again" />
{formErrors["email-again"] && (<div className="error">{formErrors["email-again"]}</div>)}
<input type="password" name="password" placeholder="Password" />
{formErrors["password"] && (<div className="error">{formErrors["password"]}</div>)}
<input type="password" name="password-again" placeholder="Password again" />
{formErrors["password-again"] && (<div className="error">{formErrors["password-again"]}</div>)}
<button disabled={!isFormValid}>Sign Up</button>
</form>
);
}