@flightdev/forms
v0.1.0
Published
Agnostic full-stack form handling for Flight Framework. Choose your validator: Zod, Yup, Valibot, or custom.
Downloads
13
Maintainers
Readme
@flightdev/forms
Form handling package for Flight Framework with Zod, Yup, and Valibot validation adapters.
Installation
npm install @flightdev/forms
# Install your preferred validator:
npm install zod # TypeScript-first
npm install yup # Schema-based
npm install valibot # LightweightQuick Start
import { createForm } from '@flightdev/forms';
import { zod } from '@flightdev/forms/zod';
import { z } from 'zod';
const contactForm = createForm({
validator: zod(z.object({
email: z.string().email(),
message: z.string().min(10),
})),
action: async (data) => {
await sendEmail(data.email, data.message);
return { success: true };
},
});Validation Adapters
Zod
import { zod } from '@flightdev/forms/zod';
import { z } from 'zod';
const validator = zod(z.object({
email: z.string().email('Invalid email'),
password: z.string().min(8, 'Too short'),
}));Yup
import { yup } from '@flightdev/forms/yup';
import * as y from 'yup';
const validator = yup(y.object({
email: y.string().email().required(),
password: y.string().min(8).required(),
}));Valibot
import { valibot } from '@flightdev/forms/valibot';
import * as v from 'valibot';
const validator = valibot(v.object({
email: v.pipe(v.string(), v.email()),
password: v.pipe(v.string(), v.minLength(8)),
}));Framework Integration
React
import { useForm, Form, Field } from '@flightdev/forms/react';
function ContactPage() {
const { register, handleSubmit, errors, pending } = useForm(contactForm);
return (
<Form onSubmit={handleSubmit}>
<input {...register('email')} />
{errors.email && <span>{errors.email}</span>}
<textarea {...register('message')} />
{errors.message && <span>{errors.message}</span>}
<button disabled={pending}>Send</button>
</Form>
);
}Vue
<script setup>
import { useForm } from '@flightdev/forms/vue';
const { register, handleSubmit, errors, pending } = useForm(contactForm);
</script>
<template>
<form @submit.prevent="handleSubmit">
<input v-bind="register('email')" />
<span v-if="errors.email">{{ errors.email }}</span>
<button :disabled="pending">Send</button>
</form>
</template>Svelte
<script>
import { createFormStore } from '@flightdev/forms/svelte';
const { values, errors, pending, register, submit } = createFormStore(contactForm);
</script>
<form on:submit|preventDefault={submit}>
<input use:register={'email'} />
{#if $errors.email}<span>{$errors.email}</span>{/if}
<button disabled={$pending}>Send</button>
</form>Solid
import { useForm } from '@flightdev/forms/solid';
import { Show } from 'solid-js';
function ContactPage() {
const { register, handleSubmit, errors, pending } = useForm(contactForm);
return (
<form onSubmit={handleSubmit}>
<input {...register('email')} />
<Show when={errors().email}>
<span>{errors().email}</span>
</Show>
<button disabled={pending()}>Send</button>
</form>
);
}Server-Side Handling
// api/contact.ts
export async function POST(request: Request) {
return contactForm.handleSubmit(request);
}API Reference
createForm Options
| Option | Type | Description |
|--------|------|-------------|
| validator | ValidationAdapter | Validation schema |
| action | FormAction | Server action |
| csrf | boolean | Enable CSRF (default: true) |
| progressive | boolean | Works without JS |
useForm Return
| Property | Type | Description |
|----------|------|-------------|
| register(name) | Function | Register a field |
| handleSubmit | Function | Submit handler |
| values | Object | Current values |
| errors | Object | Field errors |
| pending | boolean | Submitting state |
| dirty | boolean | Form modified |
Creating Custom Validators
import type { ValidationAdapter } from '@flightdev/forms';
export function myValidator<T>(schema: MySchema<T>): ValidationAdapter<unknown, T> {
return {
name: 'my-validator',
_output: undefined as unknown as T,
validate(data) {
// Your validation logic
return { success: true, data: data as T };
},
async validateAsync(data) {
return this.validate(data);
},
};
}License
MIT
