Formify Docs

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.
  • isSubmitting is managed for you around your async onSubmit.

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:

StyleExample
Config schema (recommended)validationSchema={{ email: { required: true, email: true } }}
Validation functionvalidate={(values) => errors}
Yup-like schemavalidationSchema={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

On this page