Keck Forms is a simple, type-safe React library for managing form state. It emphasizes a clean, ergonomic developer experience, enabling you to handle deeply nested forms and validation with minimal boilerplate.
- Type-Safe Form Management: Use TypeScript to ensure your forms are strongly typed.
- Nested Form State Handling: Work with deeply nested form structures and arrays for repeated form sections without breaking a sweat.
- Flexible Validation: Bring your favorite validation libraries or use custom validation methods.
- Reusable Components: Easily create reusable input components to use across your application.
npm install keck-forms
Here’s a simple form example to get you started:
import React from "react";
import { useForm, zodValidator } from "keck-forms";
import { z } from "zod";
// Define your form schema for validation
const schema = z.object({
name: z.string().nonempty("Name is required"),
age: z.number().min(0, "Age must be positive"),
});
// Define initial form data
const initialData = { name: "", age: 0 };
function App() {
// Create a Keck Form
const { form, field, FormProvider } = useForm({
initial: initialData,
validate: zodValidator(schema),
});
return (
<FormProvider>
<form
onSubmit={() => {
console.log(form.values);
}}
>
<input
value={field("name").value}
onChange={(e) => (field("name").value = e.target.value)}
onBlur={() => (field("name").touched = true)}
/>
{field("name").errors.map((error) => (
<div key={error}>{error}</div>
))}
<input
type="number"
value={field("age").value}
onChange={(e) => (field("age").value = parseInt(e.target.value, 10))}
onBlur={() => (field("age").touched = true)}
/>
{field("age").errors.map((error) => (
<div key={error}>{error}</div>
))}
<button type="submit">Submit</button>
</form>
</FormProvider>
);
}
To set up a form, define your data schema and initial values. You can use Zod or write a custom validation function.
import { z } from "zod";
const schema = z.object({
name: z.string(),
email: z.string().email(),
});
const initialData = { name: "", email: "" };
Use the useForm
hook to initialize the form. Wrap your form fields in a FormProvider
to provide context.
import { useForm } from "keck-forms";
const { field, FormProvider } = useForm({
initial: initialData,
validate: zodValidator(schema),
});
Access fields using the field()
function. Bind their value
, onChange
, and onBlur
handlers.
<input
value={field("name").value}
onChange={(e) => (field("name").value = e.target.value)}
onBlur={() => (field("name").touched = true)}
/>
For array fields, use array-specific operations like push
, remove
, or map
.
const skillsField = field("skills"); // e.g., [{ name: '', level: 'beginner' }]
skillsField.push({ name: "", level: "beginner" });
skillsField.map((skillField, index) => (
<input
key={index}
value={skillField.value.name}
onChange={(e) => (skillField.value.name = e.target.value)}
/>
));
Keck Forms supports deeply nested fields seamlessly.
field("profile.name").value = "John Doe";
field("profile.contact.email").value = "[email protected]";
Encapsulate field logic in reusable components.
function TextField({ fieldPath }: { fieldPath: string }) {
const { field } = useFormContext();
const fieldData = field(fieldPath);
return (
<>
<input
value={fieldData.value}
onChange={(e) => (fieldData.value = e.target.value)}
onBlur={() => (fieldData.touched = true)}
/>
{fieldData.errors.map((error) => (
<div key={error}>{error}</div>
))}
</>
);
}
function useForm<TInput extends object, TOutput extends object>(options: {
initial: TInput;
validate: FormValidatorFn<TInput, TOutput>;
}): {
form: TOutput;
field: GetFormFieldFn<TInput>;
FormProvider: React.FC<{ children: React.ReactNode[] }>;
};
Arguments:
initial
: The initial form state.validate
: A function or schema to validate the form.
Returns:
form
: The current validated output of the form.field
: A function to get or manipulate specific fields.FormProvider
: A context provider for the form.
function field<TPath extends StringPath<TInput>>(
path: TPath,
): KeckFieldForPath<TInput, TPath>;
Arguments:
path
: The dot-separated path to the field.
Returns:
- Field object with properties like
value
,errors
,touched
, and methods for arrays or nested objects.
push(value)
: Add a new item to the array.remove(index)
: Remove an item by index.map(callback)
: Iterate over items in the array.
Keck Forms makes form state management simple, type-safe, and efficient. Get started now!