Getting Started
Build your first form with Formify
Getting Started
Quick guide to building your first Formify form.
Your first form
The simplest way to build a form is useForm with a config-driven validationSchema:
import { useForm } from "formify-js";
interface LoginValues {
email: string;
password: string;
}
export function Login() {
const form = useForm<LoginValues>({
initialValues: { email: "", password: "" },
validationSchema: {
email: { required: true, email: true },
password: { required: true, minLength: 8 },
},
onSubmit: async (values) => {
await api.login(values);
},
});
return (
<form onSubmit={form.handleSubmit} noValidate>
<label>
Email
<input {...form.getFieldProps("email")} type="email" />
</label>
{form.touched.email && form.errors.email && (
<p className="error">{form.errors.email}</p>
)}
<label>
Password
<input {...form.getFieldProps("password")} type="password" />
</label>
{form.touched.password && form.errors.password && (
<p className="error">{form.errors.password}</p>
)}
<button type="submit" disabled={form.isSubmitting}>
{form.isSubmitting ? "Logging in…" : "Log in"}
</button>
</form>
);
}How it behaves out of the box:
- Errors appear after a field is blurred (or on submit), not while typing.
- On submit every field is touched and validated; invalid forms are blocked and the first invalid field receives focus.
isSubmittingis managed for you around your asynconSubmit.
Component style (Formik-compatible API, Formify names)
Prefer components? The API mirrors Formik 1:1 — every component is named Formify:
import { Formify, Form, Field, ErrorMessage } from "formify-js";
export function Login() {
return (
<Formify
initialValues={{ email: "", password: "" }}
validationSchema={{
email: { required: true, email: true },
password: { required: true, minLength: 8 },
}}
onSubmit={async (values) => api.login(values)}
>
<Form>
<Field name="email" type="email" placeholder="you@example.com" />
<ErrorMessage name="email" component="p" />
<Field name="password" type="password" />
<ErrorMessage name="password" component="p" />
<button type="submit">Log in</button>
</Form>
</Formify>
);
}Validation options
useForm accepts three interchangeable ways to validate:
| Style | Example |
|---|---|
| Config schema (recommended) | validationSchema={{ email: { required: true, email: true } }} |
| Validation function | validate={(values) => errors} |
| Yup-like schema | validationSchema={yupSchema} (duck-typed, no yup install needed) |
They can even be combined: config schemas validate fields, while a validate function covers cross-field rules.
Next steps
- API reference — every option and method
- Built-in validators — the
Vbuilder and config flags - Formatters — SSN, EIN, phone, currency masks on change/blur
- Async validation — unique checks, debounce, cancellation
- Plugins — extend the form lifecycle
- Try the live test app — every example plus a performance benchmark