Form

is a hook that provides a powerful yet simple way to handle form state, validation, and submission. It offers a declarative approach to form management with built-in validation, error handling, and state management.

Inspired by TanStack Form, it provides a flexible API that can handle complex form scenarios while maintaining simplicity.

accepts a configuration object and returns a that provides:

  • Field: Component for managing individual form fields
  • Subscribe: Component for subscribing to form state changes
  • handleSubmit: Function to handle form submission
  • reset: Function to reset the form to initial values
  • getFieldState: Function to get the state of a specific field
import { useForm } from "kaioken/form"

function ContactForm() {
  const form = useForm({
    initialValues: {
      name: "",
      email: "",
    },
    onSubmit: ({ state }) => {
      console.log("Form submitted:", state)
    },
  })

  return (
    <form
      onsubmit={(e) => {
        e.preventDefault()
        form.handleSubmit()
      }}
    >
      <form.Field
        name="name"
        children={(field) => (
          <div>
            <label>Name</label>
            <input
              value={field.state.value}
              onchange={(e) => field.handleChange(e.target.value)}
            />
          </div>
        )}
      />

      <form.Field
        name="email"
        children={(field) => (
          <div>
            <label>Email</label>
            <input
              type="email"
              value={field.state.value}
              onchange={(e) => field.handleChange(e.target.value)}
            />
          </div>
        )}
      />

      <button type="submit">Submit</button>
    </form>
  )
}

Form fields can be validated using the validators prop. Validation can be triggered on different events like onChange, onBlur, or onSubmit. The validator functions return error messages when validation fails.

import { useForm } from "kaioken/form"

function LoginForm() {
  const form = useForm({
    initialValues: {
      email: "",
      password: "",
    },
    onSubmit: ({ state }) => {
      console.log("Login attempt:", state)
    },
  })

  return (
    <form
      onsubmit={(e) => {
        e.preventDefault()
        form.handleSubmit()
      }}
    >
      <form.Field
        name="email"
        validators={{
          onChange: (value) => {
            if (!value) return "Email is required"
            if (!/\S+@\S+\.\S+/.test(value)) return "Invalid email format"
          },
        }}
        children={(field) => (
          <div>
            <label>Email</label>
            <input
              type="email"
              value={field.state.value}
              onchange={(e) => field.handleChange(e.target.value)}
              onblur={field.handleBlur}
            />
            {field.state.errors.length > 0 && (
              <span style={{ color: "red" }}>{field.state.errors[0]}</span>
            )}
          </div>
        )}
      />

      <form.Field
        name="password"
        validators={{
          onChange: (value) => {
            if (!value) return "Password is required"
            if (value.length < 6)
              return "Password must be at least 6 characters"
          },
        }}
        children={(field) => (
          <div>
            <label>Password</label>
            <input
              type="password"
              value={field.state.value}
              onchange={(e) => field.handleChange(e.target.value)}
              onblur={field.handleBlur}
            />
            {field.state.errors.length > 0 && (
              <span style={{ color: "red" }}>{field.state.errors[0]}</span>
            )}
          </div>
        )}
      />

      <form.Subscribe
        selector={(state) => [state.canSubmit, state.isSubmitting]}
        children={([canSubmit, isSubmitting]) => (
          <button type="submit" disabled={!canSubmit}>
            {isSubmitting ? "Logging in..." : "Login"}
          </button>
        )}
      />
    </form>
  )
}

Field Component

The Field component manages individual form fields. It provides the field state and handlers to the render function:

  • state.value: Current field value
  • state.errors: Array of validation errors
  • handleChange: Function to update field value
  • handleBlur: Function to handle field blur events

Subscribe Component

The Subscribe component allows you to subscribe to specific parts of the form state using a selector function. This is useful for rendering buttons or other UI elements based on form state.

Related