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.