Skip to main content

formisch

Form handling with Formisch, the schema-first and type-safe form library for Angular, Preact, Qwik, React, React Native, Solid, Svelte, and Vue. Use when creating forms, handling form state, validating inputs, working with field arrays, or using @formisch/* packages.

来源信息

仓库
open-circle/agent-skills
最近来源活动
2026年8月21日 21:16
检测到的 SKILL.md 语言
英语
星标
16
分支
1

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

文件资源管理器
2 个文件

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
formisch
description
Form handling with Formisch, the schema-first and type-safe form library for Angular, Preact, Qwik, React, React Native, Solid, Svelte, and Vue. Use when creating forms, handling form state, validating inputs, working with field arrays, or using @formisch/* packages.
license
MIT
metadata
{"author":"open-circle","version":"1.3"}
# Formisch This skill helps AI agents work effectively with [Formisch](https://formisch.dev/), the schema-based, headless form library for modern frameworks. ## When to Use This Skill - When the user asks about form handling with Formisch - When managing form state and validation - When working with Angular, Preact, Qwik, React, React Native, Solid, Svelte, or Vue forms - When integrating Valibot schemas with forms ## Introduction Formisch is a schema-based, headless form library that works across multiple frameworks. Key highlights: - **Small bundle size** — Starting at ~2.5 kB - **Schema-based validation** — Uses Valibot for type-safe validation - **Headless design** — You control the UI completely - **Type safety** — Full TypeScript support with autocompletion - **Framework-native** — Native performance for each supported framework ### Supported Frameworks | Framework | Package | Hook/Primitive | | ------------ | ------------------------ | -------------- | | Angular | `@formisch/angular` | `injectForm` | | Preact | `@formisch/preact` | `useForm` | | Qwik | `@formisch/qwik` | `useForm$` | | React | `@formisch/react` | `useForm` | | React Native | `@formisch/react-native` | `useForm` | | SolidJS | `@formisch/solid` | `createForm` | | Svelte | `@formisch/svelte` | `createForm` | | Vue | `@formisch/vue` | `useForm` | ## Installation ### 1. Install Valibot (peer dependency) ```bash npm install valibot ``` ### 2. Install Formisch for your framework ```bash npm install @formisch/react # React npm install @formisch/angular # Angular npm install @formisch/vue # Vue npm install @formisch/solid # SolidJS npm install @formisch/preact # Preact npm install @formisch/svelte # Svelte npm install @formisch/qwik # Qwik npm install @formisch/react-native # React Native ``` ## Core Concepts ### Schema-First Design Every form starts with a Valibot schema. Types are automatically inferred from the schema. ```ts import * as v from "valibot"; const LoginSchema = v.object({ email: v.pipe( v.string("Please enter your email."), v.nonEmpty("Please enter your email."), v.email("The email address is badly formatted."), ), password: v.pipe( v.string("Please enter your password."), v.nonEmpty("Please enter your password."), v.minLength(8, "Your password must have 8 characters or more."), ), }); ``` ### Form Store The form store manages all form state. Access it via the framework-specific hook/primitive. **Form Store Properties:** - `isSubmitting` — Form is currently being submitted - `isSubmitted` — Form submission has been attempted - `isValidating` — Validation is in progress - `isTouched` — At least one field has been touched - `isEdited` — At least one field has been edited - `isDirty` — At least one field differs from initial value - `isValid` — All fields pass validation - `errors` — Root-level validation errors ### Field Store Each field has its own reactive store with: - `path` — Path array to the field - `input` — Current field value - `errors` — Field-specific errors - `isTouched` — Field has been focused - `isEdited` — Field value has been edited - `isDirty` — Field value differs from initial value - `isValid` — Field passes validation - `props` — Props to spread onto native elements (Angular connects controls with `[formischControl]` instead) - `onChange` (React and React Native) / `onInput` (Solid, Svelte, Preact, and Qwik) / `setInput` (Angular) — Sets the field input value programmatically. Use this when the field cannot be connected to a native element. In Vue, set `field.input` directly (for example with `v-model`). Store reactivity is framework-specific. React, React Native, Solid, Svelte, and Vue expose plain reactive properties. Angular properties are signals and are called like `field.errors()`, except `path`, which is a plain value. Preact and Qwik properties are signals; use `.value` in conditions and ordinary TypeScript logic. Do not copy one framework's access syntax into another. ### Dirty Tracking Formisch tracks two inputs per field: - **Initial input** — Baseline for dirty tracking (server state) - **Current input** — What the user is editing (client state) `isDirty` becomes `true` when current input differs from initial input. ## Framework Examples ### Angular Example Angular uses signals, dependency injection, and directives instead of a JSX component API. ```ts import { Component } from "@angular/core"; import { FormischControl, FormischField, FormischForm, injectForm, type SubmitHandler, } from "@formisch/angular"; import * as v from "valibot"; const LoginSchema = v.object({ email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); @Component({ selector: "app-login", imports: [FormischForm, FormischField, FormischControl], template: ` <form [formischForm]="loginForm" [formischSubmit]="handleSubmit"> <ng-container *formischField="['email'] of loginForm; let field"> <input [formischControl]="field" type="email" /> @if (field.errors(); as errors) { <div>{{ errors[0] }}</div> } </ng-container> <button type="submit" [disabled]="loginForm.isSubmitting()">Login</button> </form> `, }) export class LoginComponent { readonly loginForm = injectForm({ schema: LoginSchema }); readonly handleSubmit: SubmitHandler<typeof LoginSchema> = (output) => { console.log(output); }; } ``` Let `[formischControl]` synchronize the native control. Do not add competing `[value]` or `[checked]` bindings except when `value` identifies an option in a radio or checkbox group. ### React Native Example React Native has no DOM `<form>` element or Formisch `Form` component. Use `handleSubmit` and bind `field.props` to `TextInput`. ```tsx import { Field, handleSubmit, useForm } from "@formisch/react-native"; import { Button, TextInput, View } from "react-native"; import * as v from "valibot"; const LoginSchema = v.object({ email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); export default function LoginScreen() { const loginForm = useForm({ schema: LoginSchema }); const submitForm = handleSubmit(loginForm, (output) => console.log(output)); return ( <View> <Field of={loginForm} path={["email"]}> {(field) => ( <TextInput {...field.props} value={field.input} autoCapitalize="none" keyboardType="email-address" /> )} </Field> <Field of={loginForm} path={["password"]}> {(field) => ( <TextInput {...field.props} value={field.input} secureTextEntry /> )} </Field> <Button title="Login" onPress={submitForm} /> </View> ); } ``` React Native text inputs are controlled, so always pass `value={field.input}`. Use `field.onChange(value)` for switches, sliders, pickers, and non-string values. ### React Example ```tsx import { Field, Form, useForm } from "@formisch/react"; import type { SubmitHandler } from "@formisch/react"; import * as v from "valibot"; const LoginSchema = v.object({ email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); export default function LoginPage() { const loginForm = useForm({ schema: LoginSchema, }); const handleSubmit: SubmitHandler<typeof LoginSchema> = (output) => { console.log(output); // { email: string, password: string } }; return ( <Form of={loginForm} onSubmit={handleSubmit}> <Field of={loginForm} path={["email"]}> {(field) => ( <div> <input {...field.props} value={field.input} type="email" /> {field.errors && <div>{field.errors[0]}</div>} </div> )} </Field> <Field of={loginForm} path={["password"]}> {(field) => ( <div> <input {...field.props} value={field.input} type="password" /> {field.errors && <div>{field.errors[0]}</div>} </div> )} </Field> <button type="submit" disabled={loginForm.isSubmitting}> {loginForm.isSubmitting ? "Submitting..." : "Login"} </button> </Form> ); } ``` ### Vue Example ```vue <script setup lang="ts"> import { Field, Form, useForm } from "@formisch/vue"; import type { SubmitHandler } from "@formisch/vue"; import * as v from "valibot"; const LoginSchema = v.object({ email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); const loginForm = useForm({ schema: LoginSchema, }); const handleSubmit: SubmitHandler<typeof LoginSchema> = (output) => { console.log(output); }; </script> <template> <Form :of="loginForm" @submit="handleSubmit"> <Field :of="loginForm" :path="['email']" v-slot="field"> <div> <input v-model="field.input" v-bind="field.props" type="email" /> <div v-if="field.errors">{{ field.errors[0] }}</div> </div> </Field> <Field :of="loginForm" :path="['password']" v-slot="field"> <div> <input v-model="field.input" v-bind="field.props" type="password" /> <div v-if="field.errors">{{ field.errors[0] }}</div> </div> </Field> <button type="submit">Login</button> </Form> </template> ``` ### SolidJS Example ```tsx import { Field, Form, createForm } from "@formisch/solid"; import type { SubmitHandler } from "@formisch/solid"; import * as v from "valibot"; const LoginSchema = v.object({ email: v.pipe(v.string(), v.email()), password: v.pipe(v.string(), v.minLength(8)), }); export default function LoginPage() { const loginForm = createForm({ schema: LoginSchema, }); const handleSubmit: SubmitHandler<typeof LoginSchema> = (output) => { console.log(output); }; return ( <Form of={loginForm} onSubmit={handleSubmit}> <Field of={loginForm} path={["email"]}> {(field) => ( <div> <input {...field.props} value={field.input} type="email" /> {field.errors && <div>{field.errors[0]}</div>} </div> )} </Field> <Field of={loginForm} path={["password"]}> {(field) => ( <div> <input {...field.props} value={field.input} type="password" /> {field.errors && <div>{field.errors[0]}</div>} </div> )} </Field> <button type="submit">Login</button> </Form> ); } ``` ### Svelte Example ```svelte <script lang="ts"> import { createForm, Field, Form } from '@formisch/svelte'; import type { SubmitHandler } from '@formisch/svelte'; import * as v from 'valibot';
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看