Formisch: one headless form library, eight frameworks, one schema
The lightweight, schema-first, and fully type-safe form library for React, Solid, Vue, Svelte and more.
At a glance
- What is it?
- Formisch is an MIT licensed headless form library from the Valibot author that runs on React, Solid, Vue, Svelte, Angular, Preact, Qwik and React Native, with validation driven by a Valibot schema and a modular methods API that keeps bundles at around 2.5 kB. The core is framework agnostic and the framework packages inject native reactivity at build time.
- Who is it for?
- Formisch is a good pick for a team that maintains the same form logic across more than one frontend framework, or that wants validation defined once with Valibot and reused on the server, because the core is framework agnostic and the per-framework packages are thin wrappers over the same schema; it is the wrong pick if you want a batteries-included component library, since Formisch is explicitly headless and supplies the state, validation and wiring rather than the markup, and before you adopt it you should check whether the framework version you use has a published package, because the framework packages ship on their own version lines.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 7 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.
Star history
- open-circle/formisch1,218 ★ · +11
| Repository | 2026-10-20 | 2026-11-07 |
|---|---|---|
| open-circle/formisch | 1.2k | 1.2k |
11 Stars in the last 18 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Headless, schema-based, and small
Formisch is a schema-based, headless form library for JavaScript frameworks, and the three words in that description each rule something out.
Headless means there are no components to style. The library gives you form state, validation and the wiring between an input and its error message, and you render the markup. The form element is a thin layer around the native form element that handles validation and submission, and the inputs are native HTML form fields, which the highlights list confirms with the line that it supports all native HTML form fields.
Schema-based means validation is defined with Valibot, and the schema does double duty: it describes the shape of the form data and it provides the types. The useForm hook initializes the form's store based on the provided Valibot schema and infers its types, so there is no second description of the form to keep in sync.
Small is quantified. The highlights list a small bundle size starting at 2.5 kB, and the comparison section explains where that comes from: a modular methods API keeps bundles starting at just around 2.5 kB by only including the methods you import. That is tree-shaking done deliberately, by making the API surface a set of independent functions rather than one object with everything on it.
The other highlights are type safety with autocompletion in the editor, fine-grained DOM updates, and a minimal, readable API.
The documentation site is formisch.dev, and there is a playground on StackBlitz for React.
The React example is the whole API in one screen
The README's React example is worth reading in full, because it shows the entire model rather than a fragment of it.
import { Field, Form, useForm } 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,
});
return (
<Form of={loginForm} onSubmit={(output) => console.log(output)}>
<Field of={loginForm} path={['email']}>
{(field) => (
<div>
<input {...field.props} value={field.input} type="email" />
{field.errors && <div>{field.errors[0]}</div>}
</div>
)}
</Field>
<button type="submit">Login</button>
</Form>
);
}There are three pieces. useForm creates the store from the schema. Form wraps the native form element and receives the parsed output on submit, so the value you get in onSubmit is validated and typed, not raw input. And Field is a render-prop component scoped to a path in the form, giving you field props to spread onto the input, the current input value, and the errors for that field.
Two details are worth copying verbatim rather than improvising. The field props are spread onto the input so the library receives the events, and the value is bound separately, because the library owns the state and the input is a controlled component. And the error rendering is guarded with field.errors, so nothing is rendered for a field that is valid or untouched.
The path is an array, so a nested field is a longer array, and the type safety covers deeply nested paths and field arrays with TypeScript inference that stays fast even as forms grow.
The methods API is the escape hatch
Beyond the component API there is a set of functions, which the project calls methods, for reading and manipulating the form state programmatically. The list is long and deliberately named after what they do.
The read side is focus, getDeepErrorEntries, getDeepErrors, getDirtyInput, getDirtyPaths, getErrors, getInput, isDirty, isEdited, isTouched and isValid. The write side is insert, move, remove, replace, reset, setErrors, setInput and swap. And the flow side is handleSubmit, submit and validate.
The split into three groups is the useful part. isDirty, isEdited and isTouched are three different notions that a form library often conflates, and having them as separate names forces you to decide which question you are asking. A field can be edited but not touched, or touched but not dirty, and a form that wants to warn about unsaved work needs the right one of the three.
The array methods, insert, move, remove, replace and swap, are what make field arrays workable. A form with a repeating list of rows needs to add a row at a position, take one out, and reorder, and doing that with a plain setInput on a path would be clumsy. Having first class array methods is the difference between the library supporting field arrays properly and supporting them in principle.
The modular design is the other thing to notice. Because each method is an independent export, importing one does not pull in the others. That is where the 2.5 kB figure comes from, and it is also why the framework packages can expose the whole API without the framework package itself being heavy.
How a framework agnostic core stays native
The comparison section explains the mechanism, and it is the most interesting technical claim in the project.
What makes Formisch unique is its framework-agnostic core, which is fully native to the framework you are using. It works by inserting framework-specific reactivity blocks when the core package is built, giving you native performance for any UI update.
So the core is not a library that sits next to your framework and polls it. At build time, the framework package injects the reactivity primitives of that framework into the core, so a field update triggers the framework's own signal mechanism rather than a subscription list the core maintains.
That is what makes the fine-grained DOM updates claim possible in every framework at once. A reactive system that has to work across eight frameworks would otherwise have to normalise to the slowest common denominator, which usually means re-rendering a component subtree. Injecting native reactivity means the smallest possible update, in each framework, with the framework's own scheduling.
The vision section states the ambition in the author's own terms: to create a framework-agnostic platform similar to Vite, but for forms, a shared core that lets the same mental model and codebase work natively across every modern UI framework. That structure of a shared core plus per-framework packages is exactly the repository's layout.
The project is by Fabian Hiller, who is behind Valibot, and the schema-first approach is a direct consequence of that: Formisch does not invent a validation language, it consumes one that is already designed to be small and modular.
Eight frameworks, and the packages ship separately
The supported framework list is the broadest part of the claim, and it is worth reading as the actual scope of the project.
The list is Angular, Preact, Qwik, React, React Native, SolidJS, Svelte and Vue. That is eight, from the two ends of the ecosystem, and the package names follow a pattern: @formisch/react, @formisch/vue, @formisch/solid, @formisch/svelte, @formisch/angular, @formisch/preact, @formisch/qwik and @formisch/react-native. The README links each one to its directory under frameworks/ in the repository.
The release history shows how those packages are versioned. The most recent releases are v1.1.0-vue, v1.1.0-svelte and v1.1.0-solid, all on the same day in September 2026, and the suffix in each tag names the framework. So the framework packages are versioned independently of each other, which is the only workable arrangement when a core release has to reach eight ecosystems and some of them will be slower to adopt.
Practically, that means a project on two frameworks can pin two different versions of Formisch, and the two do not have to be released in lockstep. It also means the framework package you use is the thing to check for compatibility rather than the core.
The repository layout follows the same structure. There is a packages/ directory for the framework-agnostic core, a frameworks/ directory with the per-framework packages, examples/ with a svelte-invoice-form example, playgrounds/ for the StackBlitz setups, a website/ directory for formisch.dev, and a pnpm-workspace.yaml tying it together. The root package.json is a pnpm workspace with the packageManager pinned to [email protected] and engines requiring Node 22 or newer.
Where Formisch is the wrong choice
The first limitation is the headless one, and it is worth being concrete about it. There is no component library here. Formisch gives you state, validation and the plumbing, and you write the label, the error text, the layout, the loading state and the submit button styling yourself. If what you want is a set of accessible form components with a consistent look, this is the wrong library and you should be looking at a component library instead.
The second is the Valibot dependency. The schema language is Valibot, not something Formisch defines, and the whole type inference story rests on it. That is a strength if you already use Valibot, since you define the shape once and reuse it for server validation. It is a constraint if you do not, because you are adopting a second library and a particular schema dialect along with the form library.
The third is the framework coverage in practice. Eight frameworks are listed, but the release history shows a version of 1.1.0 per framework, which is early for a library with a 2.5 kB bundle promise and an ambitious architecture. A framework with fewer users, or one that changes its reactivity model between major versions, will be slower to be supported, and the injection-based design means the framework package has to be rebuilt when the framework's primitives change.
The fourth is scope. Formisch is about forms. Field arrays, nested objects and validation are covered, but there is no story in the README about async server-side validation, about pending states while a field is being checked remotely, or about optimistic updates. Those patterns are the ones that get hard in any form library, and a headless design means you build them yourself.
The last point is about the ecosystem rather than the code. The project is young, its releases are recent, and its author maintains Valibot as well. A team that needs long-term support for a form layer will want to know how much of that depends on one person, and the sponsors and partners section suggests the answer is a small group.
Editorial conclusion
Formisch is a good pick for a team that maintains the same form logic across more than one frontend framework, or that wants validation defined once with Valibot and reused on the server, because the core is framework agnostic and the per-framework packages are thin wrappers over the same schema; it is the wrong pick if you want a batteries-included component library, since Formisch is explicitly headless and supplies the state, validation and wiring rather than the markup, and before you adopt it you should check whether the framework version you use has a published package, because the framework packages ship on their own version lines.
Frequently asked questions
What is Formisch and which frameworks does it support?
Formisch is a schema-based, headless form library that manages form state and validation. The supported frameworks are Angular, Preact, Qwik, React, React Native, SolidJS, Svelte and Vue, each with its own package such as @formisch/react or @formisch/vue.
How do I define validation in Formisch?
With a Valibot schema, which doubles as the type source. The useForm hook initializes the form store from the provided schema and infers its types, and the Form component's onSubmit receives the validated and typed output rather than the raw input values.
How does Formisch keep its bundle size small?
Through a modular methods API that only includes the methods you import, which keeps bundles starting at just around 2.5 kB. The framework-agnostic core stays framework native because framework-specific reactivity blocks are inserted when the core package is built, giving fine-grained DOM updates in each framework.
What can I do with the Formisch methods API?
Read the form state with focus, getDeepErrorEntries, getDeepErrors, getDirtyInput, getDirtyPaths, getErrors, getInput, isDirty, isEdited, isTouched and isValid, manipulate it with insert, move, remove, replace, reset, setErrors, setInput and swap, and drive the flow with handleSubmit, submit and validate.
What licence is Formisch released under?
MIT, with the licence text in LICENSE.md at the repository root. The package is marked as an ES module, requires Node 22 or newer, and the most recent releases are v1.1.0-vue, v1.1.0-svelte and v1.1.0-solid.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/open-circle-formisch)Star history chart for your README
[](https://hysenlabs.com/projects/open-circle-formisch)Was this useful?