open-circle/agent-skillsMIT2 files

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.

Specification
Skill ID
open-circle/agent-skills/formisch
Publisher
open-circle
Repository
agent-skills
Installs
0
Files
2
License
MIT
Synced
Sep 23, 2026
How to use it

Open any RiverX project, open the Skills panel in the chat, and search for this identifier. The files are fetched from the source repository at install time.

open-circle/agent-skills/formischInstalls these files
  • .claude-plugin/plugin.json
  • SKILL.md

What this skill tells the agent

Formisch

This skill helps AI agents work effectively with Formisch, 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

FrameworkPackageHook/Primitive
Angular@formisch/angularinjectForm
Preact@formisch/preactuseForm
Qwik@formisch/qwikuseForm$
React@formisch/reactuseForm
React Native@formisch/react-nativeuseForm
SolidJS@formisch/solidcreateForm
Svelte@formisch/sveltecreateForm
Vue@formisch/vueuseForm

Installation

1. Install Valibot (peer dependency)

npm install valibot

2. Install Formisch for your framework

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.

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.

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.

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

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>
        )}

Use this skill in a project

Open any RiverX project, search the Skills panel for open-circle/agent-skills/formisch, and install it in one click.

Use this skill