Skip to content

About

A self-hostable form engine, renderers and backend for React and Angular. One engine in browser and server, your design system's markup, Apache-2.0.

Topics

Resources

Contributing

Security policy

Stars

15 stars

Watchers

0 watching

Forks

Latest commit

 

History

487 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

formancy.ai

Website: formancy.ai CI Codecov coverage npm version: @formancy/core License: Apache-2.0 Node.js: >=22.12.0 Status: beta

Build the form. Ship your product.

The open-source visual form builder for Angular and React.

From a simple signup to a multi-step application: build it visually, add rules, and make it yours. Embed your form in Angular or React with your own design system. Conditional questions, live validation and calculated totals are already part of the toolkit.

Your forms. Your design. Your infrastructure. Use the renderer in your app, then add the optional backend for submissions, file uploads and workflows. Apache-2.0 throughout.

The formancy landing page: a working form preview on the right, its appearance switchable between four themes and its total calculated by the engine

Design it. Add rules. Put it to work.

  1. Build your form. Choose fields, arrange them in rows, sections or pages, and preview the result. Use drag and drop or keyboard controls, with undo.
  2. Set the rules. Show follow-up questions based on previous answers, make fields required when relevant, and calculate values such as totals.
  3. Use it in Angular or React. Save the form definition as JSON and render it with the native framework components. Start with a theme or connect your own design system.
  4. Collect answers on your infrastructure. The optional backend checks submissions with the same rules, stores them in PostgreSQL, and provides drafts, file attachments — scanned by ClamAV before they are kept, if you run it — CSV export, webhooks and an audit log.

The visual editor is built in both Angular and React, over one shared core that decides what any edit may do — so the two cannot offer different answers for the same document — and the forms it creates render in either. You can also author the JSON directly or use a coding agent through MCP. The shared engine handles validation and calculations, so you do not need to implement each rule separately in your UI and the formancy backend.

Status: beta, version 0.5.0.

Every spec version is frozen. Each only adds, so an older document keeps working and its submissions keep their shape — upgrading is one line and nothing rebinds (0051, 0140). MIGRATIONS.md lists what each version added.

The direction that costs something is the other one. A reader pinned to an older release refuses a newer document rather than ignoring the part it cannot read — loudly, on purpose, because the alternative is a form with a missing question and a submission with a missing answer. Upgrade the readers before the documents.

The package APIs are not frozen — they will change before 1.0. They are published to npm from CI with provenance under the @formancy scope.

The server is not ready for a public deployment, though its documents no longer name a single gap as the reason. It has authentication, role-based authorization, forms that are private until opened, per-IP rate limits counted once across replicas, a request body cap, a publish-time check that refuses regular expressions which can be made to backtrack, an audit log, a request log with no field for an answer or a credential, replies to a failure on the server that say nothing of what was thrown, drafts that carry their own key, a proof-of-work challenge for anonymous submissions, and a token every form is handed out with so that a response sent twice is stored once (0169). What it knowingly lacks is recorded, with what each costs, as debt in arc42 §11.2 and as residual risk in the safety analysis. Among it: while its rate-limit counter cannot answer, the public plane has no limit and nobody can sign in; a limit per address does not slow anybody with many addresses; and webhooks want a single replica. Read both before putting it in front of the public.

What you can build

Your form should look like your product

One event-registration form rendered four times — in the Paper, Blueprint, Dusk and Pop themes — with the same answers typed in and the same calculated total

One event registration form, four themes, the same answers typed into each. Change its appearance without rewriting its fields or rules — the renderers are unstyled by default, so a supplied theme, your own CSS or your own components all reach the same markup.

Every one of them says 490 because the engine calculated it from the selected pass, in the browser, as the radio was clicked. With the formancy backend, that total is recalculated on submission rather than trusted from the browser. The same four themes are on the landing page, switchable while you type into the form.

Add a field. Set a rule. See it work.

The self-hosted admin editing a conference registration: the structure tree with a nested group and a repeater, a live two-column preview with a grid of colleagues and a calculated total, and beside it the form's examples, all holding, above the property panel for the selected field

A real registration form, open in the admin: a group of attendee details, a pass that decides which questions follow, two dates with bounds, a grid of colleagues on one invoice, a file and a total the engine calculates.

Add and organise fields in the structure tree, see the form in the live preview, and edit labels, validation and other settings in the property panel — each with a sentence saying what it does to the data. Arrange fields side by side or into sections by drag or by keyboard. Above the properties, the form's own examples run after every edit, and a publish names any it would stop holding. The admin reopens published forms and reports which changes would invalidate the submissions you already have.

Click an answer. Watch the form adapt.

The playground on a wide screen: the builder holding a request to carry to a model of your own, the same form rendered by React and by Angular side by side with the same answers typed into each, and the engine's submission value and tracked fields

Use the visual builder or edit the JSON in the playground. The form is rendered twice — once by Angular and once by React — from one schema over two engines built from it, side by side on a wide screen and one below the other on a narrower one, so the claim that the engine is framework-neutral is something you can look at rather than something this file asserts. Try conditional questions and validation, ask a model of your own for a change through the relay, and inspect the answers that would be submitted. Switch language or theme without reloading. pnpm --filter @formancy/playground dev runs it locally.

Six reasons to build with formancy

  • The builder is open source, too. The visual editor, Angular and React renderers, and optional backend are all Apache-2.0. Inspect, adapt and host the whole stack yourself.
  • Your forms evolve. Answers keep their context. Each submission keeps the exact form version used to collect it. Review compatibility, potential information loss and breaking changes before publishing an update.
  • Two frameworks. One tested contract. Angular and React render the same form definition and run through the same behaviour and accessibility test suite. Support for both is continuously checked.
  • Catch broken rules before your users do. Publishing checks form structure and expressions, including invalid references, cycles and supported type errors. The same checks help validate forms written by coding agents.
  • Your components. Your design system. Connect your own field components and styles, or start with a supplied theme — or, in Angular, with Angular Material, held to the same conformance fixtures as the defaults; an Angular starter puts the builder and a Material form side by side, and formancy.ai/angular-form-builder runs it in the page. The shared engine handles the rules while you control how the form fits your product.
  • Tested on the versions it declares. React 19.0 and the newest 19, Angular 22.0 and the newest 22, Node.js 22.12 and 24 — each a CI run; the compatibility page says what each proves.
  • Accessibility built in. Continuously checked. Designed with WCAG 2.2 in mind: keyboard editing, connected labels, help text and error messages, plus automated accessibility checks in both renderers. Your finished form still needs review with its own components, colours and content; automated tests alone do not establish WCAG conformance.

The hard parts of forms, already connected

  • Conditional fields and calculations. Build questions that adapt to previous answers, conditional required fields and automatically calculated totals. The condition editor writes "(A and B) or C", offers the comparisons a field can take and a value control of the field's own kind, and guards every read so a rule never fails open on an empty form — or in a fresh repeater row, where a rule compares the fields of its own row; CEL is there for the rest. A rules overview lists every rule in words and, against a preview's answers, says why a field is hidden or required now — including a rule that cannot be decided.
  • Files and formatted text. Collect attachments with type and size limits — each file its own upload, with its progress, a way to cancel or retry it, a place in the order, and a picture of an image — and let people write answers with bold, italic, links and lists.
  • Validation in the browser and on the server. Give immediate feedback, then check submissions again with the same rules in the formancy backend.
  • Keyboard controls and accessibility checks. The engine connects labels, descriptions and errors. Both renderers are checked with axe-core in the shared conformance suite.
  • Form versions and submission history. Each submission keeps the form version used to collect it. Review changes before publishing an update.
  • A visual theme editor. Every design token the applied theme declares, read from its stylesheet rather than from a list — so it works on a theme you wrote, and what it hands back is a CSS patch that keeps inheriting rather than a fork. That patch is the preset: import it and the editor opens where you left it, and says what in the file it could not apply.
  • Ratings and sliders. A scale is a number field with a widget on it, so the answer is the same number either way — and a rating is a radio group rather than a row of buttons, which is one tab stop instead of eleven.
  • Choices with pictures. A radio group or a set of checkboxes can show a picture with each option, inside its label, so the picture chooses it and its description is part of the option's name. Never on a dropdown, which cannot show one.
  • Input masks that store the number, not its spelling. (999) 999-9999 shapes how a phone number is typed and stores 5551234567. Where a typed, deleted or pasted character lands is decided once for both renderers, and the server refuses an answer that does not fill the mask, because the engine does.
  • AI-assisted authoring. Describe a change in the builder, have a model translate what a language is missing or draft examples from what you say the form should do — every answer checked, diffed and reviewed before it lands — or give your coding agent the MCP tools to author and validate a form definition. On formancy.ai you carry each request to your own Claude and paste the answer back; a self-hosted server can hold the model instead — Claude, OpenAI's models or Grok, the operator's choice — with the key on the server rather than in a browser.
  • Every word in the reader's language. The questions come from the form's own catalogue, and the renderers' own words — Next, Submit, a row's buttons, what a field announces while a file is sent — follow them, in English, German or French, or a language you add a message at a time.
  • No third party in the loop. Spam protection is proof of work computed in the visitor's browser and verified with your own key, not a captcha service. formancy.ai and the admin load their fonts and editor from themselves, and a browser test fails the site on any request to another host.
  • Apache-2.0, all of it. The spec, engine, renderers, builder and backend.

Start from a template

The starter collection covers HR, sales, customer service, events, operations and healthcare administration. Each template is a plain JSON form with English, Swiss High German and French text, a fictional sample and executable behaviour cases. Browse Templates to preview or download a form, then open it in the playground to edit it and try both renderers. You can also copy its *.form.json straight into your app. The forms use frozen spec version 2 and need no external services.

Integrate a form into your app

Install the renderer for your framework:

npm install @formancy/react @formancy/core @formancy/spec    # React 19
npm install @formancy/angular @formancy/core @formancy/spec  # Angular 22

ESM-only, Node >= 22.12. The framework package is a peer dependency, so you keep the React or Angular version you already have. The backend is a container rather than a dependency — see running the stack.

The builder ships as two packages over one core — @formancy/builder-react and @formancy/builder-angular, both published. What decides anything is in @formancy/builder-core and shared, so the two cannot offer different destinations for the same document (0091). Both carry both trees, the property panel, the condition editor, the translations pane, the drop surface over the rendered form, and the prompt pane — describing a form in words, and reviewing what the answer does before it lands, with the form's examples run against it so the review names any it would stop holding (0159). The model is the host's AskModel. formancy's server can be that model: name Anthropic, OpenAI or xAI, a key and a model, and the key stays on the server, which asks under the briefings it writes itself and never one from the request. That narrows what the key can be spent on to formancy's three kinds of request; it does not close it, since the person's instruction is free text. The admin asks it (0165). For a page that may not call one, both carry a relay pane, where a person copies each request to a chat of their own and pastes the answer back, and every check after the paste runs in the page (0160). Given that model, the translations pane asks it for the messages a language is missing, and holds the answer for review message by message — the source beside what is proposed, and the form as it would read — before it lands; a translation somebody made is never replaced (0161). Given the same model, both scenario panes draft examples from what the author says the form should do, showing the model the form's fields and never its rules, and the author keeps each one with the engine's verdict beside it (0162). Each of those three runs can be held by the host rather than the pane that asked, so a turn outlives the tab it was asked under: a translation is held for its language and drafts for their form (0163, 0164). Both save a field as a block to use again — with the rules that live inside it and the words it names — and insert one with its keys made unique and its rules following them; the host keeps the blocks (0135). Both speak the author's language — their own words, the spec's property labels, and why the validator refused an edit: English, German and French are shipped, a host can add its own catalogue a message at a time, and the playground's Language switch shows it (0114, 0122).

How it fits your stack

The editor saves a form definition containing fields, layout and rules. Your application renders that definition, and the optional backend validates and stores the submitted answers. These pieces share the same form model:

  • One engine, browser and server. The same compiled validation, conditional-logic and calculation engine runs in both places, so client and server rules cannot drift.
  • Your design system owns the markup. Headless by default — the component kit ships zero CSS, and you can drop to prop getters and render every element yourself.
  • Apache-2.0, with no paywalled essentials. The spec, engine, renderers, builder and self-hostable backend are free forever.

Layout

packages/spec           schema types, JSON Schema, canonical hash, diffing,
                        i18n and layout resolution
packages/expressions    CEL parse/check/compile/evaluate + deterministic metering
packages/core           the headless reactive engine (rules, rows, wizard, a11y ids),
                        and the renderers' words in each language (core/words)
packages/react          React binding: hooks, unstyled components, error summary
packages/angular        Angular binding: signals over the same protocol, zoneless
packages/conformance    the behaviour + accessibility contract, published so another
                        renderer can be held to it
packages/builder-core   headless schema editing: commands, undo/redo, valid
                        targets, and everything a builder's UI reads off a
                        session — shared by both builders
packages/builder-react  the builder UI for React: structure tree, arrangement
                        tree, field palette, property panel, logic —
                        keyboard-first, with drag as a second route
packages/builder-angular  the same builder for Angular: zoneless, one signal per
                        session, the same commands and the same destinations
packages/server-core    backend use-cases against storage ports
packages/server         Fastify + Postgres: publish, resolve, replayed submissions,
                        drafts with lazy migration, files (local or S3, scanned
                        by ClamAV if you run it), webhooks, CSV export, a form's
                        examples run at publish, and an opt-in model adapter
packages/themes         reference themes. Nothing depends on them
packages/tiptap         a TipTap editor held to formancy's rich-text grammar
packages/challenge      the proof-of-work challenge: mint, solve and verify
packages/mcp            formancy as tools for a coding agent (MCP)
apps/site               formancy.ai — the landing page, which renders a real form
apps/playground         the one-screen demo (editor / live form / engine state)
apps/angular-starter    an Angular application: the builder and a Material form
apps/admin              the self-hosted admin: build, publish, versions,
                        submissions, examples, and the server's model if set
apps/docs               the documentation site (Astro Starlight)

The builder edits two documents over one model. builder-core holds the document, the undo stack, the rules about which edits are legal, and what any builder's interface reads off a session. builder-react is the interface over it, in two trees, and builder-angular carries the same two:

  • Structure — what the form collects. Fields, groups, pages and repeaters, with a palette, a property panel generated from the spec's own JSON Schema, and conditions that compile to CEL.
  • Arrangement — where it appears. Rows, columns and sections, which is how two fields end up side by side.

Both are entirely keyboard-driven, and both grew a drag surface afterwards, deliberately in that order. Rows and columns can also be dragged on the preview itself — the rendered form is a drop target, going through the same commands, so the two views cannot disagree (0050).

Development

Requires Node >= 22.12, pnpm (via corepack enable pnpm), and Docker (for the server's integration tests and the dev database).

pnpm install
pnpm build
pnpm test        # server tests start a disposable Postgres via Testcontainers
pnpm typecheck

Run the stack locally

docker compose up -d                    # Postgres on :5439, API on :4380

That builds and runs the server image. It refuses to start until you have secrets:

cp .env.example .env
# then fill in FORMANCY_AUTH_SECRET, FORMANCY_ADMIN_EMAIL and
# FORMANCY_ADMIN_PASSWORD — .env.example has a one-line generator

There are no defaults, here or in the image. A form platform that boots with a signing key printed in its own repository is one that anyone who has read the repository can forge a session for. The admin is created only while no user exists, so it cannot re-seed an admin into a running installation.

To work on the source instead, run only the database and start the server from the workspace:

docker compose up -d postgres           # Postgres on :5439

DATABASE_URL=postgres://formancy:formancy@localhost:5439/formancy \
  pnpm --filter @formancy/server dev    # API on :4380

pnpm --filter @formancy/admin dev       # admin on :4382 (proxies /api)
pnpm --filter @formancy/playground dev  # playground on :4381
pnpm --filter @formancy/site dev        # formancy.ai on :4384

Those ports are fixed rather than "the next free one", so a stale dev server is an error you see immediately instead of a page at an address nobody was told about.

The admin

The admin has a build tab — the keyboard-driven builder in a three-pane inspector, beside a live preview, switching between the structure and the arrangement in the pane header — plus the raw schema editor, translations, a tab to fill the published form in against the server as a respondent would, publish, version history, submissions with a CSV export whose columns are unioned across schema versions, and webhooks. A published form's examples are kept by the server beside it: the build tab runs them after every edit, and every publish runs them against the version it replaces and names, on the 201, each one that stops holding — a warning, never a refusal (0166). When the operator names a model — Anthropic's, OpenAI's or xAI's, with its key on the server — the build tab can describe a change in words and draft examples through it, the translations tab can ask it for what a language is missing, and each says which provider and model a request goes to before anybody asks (0165).

Use it from a coding agent

claude mcp add formancy -- npx -y @formancy/mcp

Nine tools. Five of them — describe_spec, validate_form, diff_forms, check_scenarios and the checking half of publish_form — need no server and no credentials, so an agent can write a whole form and be told exactly what is wrong with it before anybody deploys anything. Set FORMANCY_URL and FORMANCY_API_KEY together to add publishing and reading submissions.

Every tool says what it will do before it is called — read-only or not, open world or closed — so a host can run the five local checks without asking and still stop at a publish. Each answers with a structured result beside the prose rather than JSON glued to the end of a sentence. And three prompts ship with the server: build_a_form, change_a_form and embed_a_form, which give the order rather than the tool names — a model that writes a document before calling describe_spec has already invented type: "email".

check_scenarios is the one that catches a rule written backwards. leaveType == 'other' and leaveType != 'other' are both valid CEL and both pass every other check here — the difference is between the document and what somebody meant, and the only thing that can see it is an example with its answer written down.

Changing a form that already exists is two calls, not one. propose_form_edit holds the edit up against what is published and answers with what it would cost submissions already collected — then publish_form takes the hash it gave you and refuses if the form moved in between. A document is the whole form, so publishing one based on an older version silently reverts whatever somebody published while you were working.

The point is not that the API is reachable by prompt. It is that a model writing a form is a model writing logic, and this is the one product category where the logic can be checked before the form exists: the document format has a published JSON Schema, and CEL type-checks. Ask an agent for seats * 4 and it is told

no such overload: double * int. This evaluates to nothing for every value anybody enters […] write the literals with a decimal point — 4 becomes 4.0.

rather than publishing a form whose total silently stays empty (0056).

Build formancy.ai

The website is one static deployment, composed by scripts/build-web.mjs: the landing page at / with its Templates and Angular pages at /templates/ and /angular-form-builder/, the playground at /playground/, the documentation at /docs/, and the Angular starter at /angular-form-builder/demo/, which the Angular page embeds.

pnpm build:web                          # -> apps/site/dist

Each app is its own build, because each is its own product — and serving them together is a copy. Each is built knowing where it is served from, which is the part that is easy to get wrong and impossible to notice: Vite writes absolute asset URLs, so a playground built at the default base asks for /assets/index-<hash>.js, which is the site's asset directory. The page loads, the script 404s, and the deployment is a blank screen while every build log says it succeeded. scripts/build-web.mjs reads each built page back and refuses to finish if that has happened. The starter, served inside another page, is built with a relative base instead.

Deploying is whatever serves a directory. With Cloudflare:

pnpm build:web                          # build command
cd apps/site && npx wrangler deploy --assets=dist   --name=formancy-ai --compatibility-date=2026-09-18

The playground is the one-screen demo: schema or builder on the left, the live form in the middle, the engine's actual state on the right. Under Build, Fields, Arrangement, Rules and Translations are views of one document — move a field into a row in either tree, or drag it on the form itself, and all three panes follow; Rules says every rule in words and, from the answers typed into the form, why a field is hidden or required now. Beside the fields, each form's own examples run after every edit. The switchers are not decoration either.

Theme proves the headless claim: the renderers ship no CSS, and two themes that look like unrelated products swap live with no remount and no component change.

Language proves the i18n section. The demo form's labels are $t references into three catalogues, and French is deliberately incomplete — switch to it and the labels nobody has translated stay English, because a missing translation falls back to the default locale rather than printing a message id at somebody. The renderers' own words switch with it — Submit, a row's buttons, what a field announces while a file is sent — in both panes, because they are read in the form's language from one catalogue both renderers share (0171). The builder's Translations tab is the other side of it: choose French there, in either builder, and every message still to translate is marked beside its English — and a model of your own can be asked for them, through the same relay as describing a change, with each message reviewed before any of it lands.

Describe a change in words under Fields, in either builder, and the playground shows the exact request it would send a model — it calls none, because formancy.ai asks no other site for anything. Copy it into a chat of your own, paste the answer back, and the answer is checked, diffed against the form and held for review like any model's. Copying puts the whole request on your clipboard, the form included, and pasting it into a chat gives it to that service under your own account (0160). While your chat answers, look at anything — the JSON, another tab, the other builder: the request waits above the tabs, and the answer pasted then is held for review under Fields, in either builder (0163). The same holds for the French asked for under Translations, which opens on French again, and for examples drafted under Fields (0164). Not sure what to ask? On the starter each of the three suggests something beside its box: a change whose rule the starter's examples catch if the answer turns it round, one no form can do, which a model is asked to decline, the French the starter left unfinished, and a sentence to draft examples from. One with words fills in the box and asks nothing; the French one, while the French is missing something, puts its request at the top of the builder, for you to carry.

?dir=rtl opens the playground right to left: both forms and both builders follow the reading order — the marks on a selected node move to the side a line starts on, and a field dragged onto the rendered form lands on the side it was aimed at (0123).

Accessibility

Not a workstream beside the code — a property of passing the tests.

A renderer whose markup cannot be reached by role and accessible name fails the conformance suite. The drivers are forbidden from using test ids or CSS selectors, so a control a screen reader cannot find is a control no test can drive (0034). axe-core runs after every mount and every DOM-mutating change.

The engine owns ids and ARIA composition (0021), so both renderers wire them identically rather than each getting it slightly wrong: aria-invalid only when validated and invalid, aria-required reactive because requiredness can be expression-driven, real fieldset/legend for groups, exactly one polite live region per form, and an error summary that takes focus without role="alert" — focusing it already announces it.

Side-by-side layouts are where reading order and visual order most easily come apart, so four criteria shape how they are built:

Criterion What it forces
1.3.2 Meaningful Sequence Children are emitted in the layout's declared order; the stylesheet places them by source order alone — no order, no explicit grid-column
2.4.3 Focus Order Follows from the same rule: tab order is DOM order is visual order
1.4.10 Reflow A row becomes one column when there is no width for two, via auto-fit/minmax — a media query, not a measurement. A layout that reflows only after scripts run does not reflow
1.3.1 Info and Relationships A row is presentation and gets no semantics; a labelled section is visibly grouping fields, so it is a real role="group" with an accessible name. An unlabelled one stays a plain box, because a group with no name announces "group" and tells nobody anything. A table is a grid and not a <table>: arranging fields in columns is not tabular data, and the markup would announce rows and columns that mean nothing

Tabs are presentation, unlike pages, and everything about them follows from that one fact.

Criterion What it forces
4.1.2 Name, Role, Value The full ARIA tabs pattern: tablist, tab, tabpanel, aria-selected, aria-controls. A strip may be named, because two strips in one form are otherwise both announced as "tab list"
2.1.1 Keyboard Arrows move between tabs, Home and End reach the ends, and the strip is one tab stop through a roving tabindex — twelve tabs must not cost twelve presses to get past
3.3.1 Error Identification A field in a closed tab is still validated and still submitted, so the error summary can send focus to it. Focusing a control inside a hidden panel does nothing at all, so the strip opens the tab focus lands in — without that, a reader is told the form has an error and sent nowhere
1.4.1 Use of Colour Which tab is open is carried by weight, background and a border as well as by colour
2.5.8 Target Size A tab is at least 24 CSS pixels tall, which is exactly where a tab strip is tempting to shrink

A formatted-text answer is never HTML. It is stored as a small closed grammar, parsed once into a typed tree, and rendered as elements by both renderers — so there is no path from an answer somebody typed to innerHTML, and a javascript: link renders as the text they wrote (0052). That is a security decision before it is an accessibility one, but it is the same principle: the safe thing is the structural thing, not the thing a consumer has to remember.

The website holds itself to this too. formancy.ai passes at 320 CSS pixels with no horizontal scrolling, and prefers-reduced-motion removes every scroll effect in the stylesheet rather than in script (0053). A page that makes somebody ill while they read the part about accessibility has refuted itself.

The builder is keyboard-first, and its drag surfaces were added afterwards on purpose: 2.5.7 requires every dragging movement to have an equivalent alternative, and building the alternative second is how it ends up unfinished (0046). That holds for all three of them — the structure tree, the arrangement tree and the preview itself. Each drag calls the same commands the keyboard does, offers only drops the session will accept, and announces through the same live region. The keyboard move palette names destinations as sentences rather than coordinates: "Row with First name and Last name, between First name and Last name" is a choice somebody can make without seeing the screen, and { parent: [0], index: 1 } is not.

What this is not. Automated checking catches roughly 57% of machine-detectable issues by Deque's own figure, and about 30% of WCAG 2.2 criteria are machine-testable at all. No manual screen-reader audit has been performed and no VPAT is published. The claim is "built to be accessible and tested to a floor", not "conformant".

Documentation

Two sets, for two different questions.

How to use it — apps/docs, an Astro Starlight site with quickstarts for React and Angular, the concepts, and a spec reference generated from the JSON Schema.

Why it is built this way — docs/:

Releases

CHANGELOG.md — what is in each version, and what is knowingly missing from it. RELEASING.md — how a release is cut, and what the pipeline signs and attests.

Releases are published from CI with npm provenance, and each one carries a CycloneDX SBOM signed with cosign.

0.5.0 is the current beta. Every package under the @formancy scope moves on one version number, so any two of them at the same version are known to work together — which is what makes the support matrix size one (0009). Each tarball carries a SLSA v1 provenance attestation binding it to the workflow run, commit and repository that built it. There is no signing key, so there is none to leak. Check one yourself:

npm install @formancy/core
npm audit signatures

The list of packages is not repeated here, because a list in prose goes stale and this one did: it said ten, and @formancy/builder-react — the package a prospective adopter most wants to see — was the exception that "lands in the next release". It lands in this one, along with @formancy/challenge, @formancy/mcp and @formancy/tiptap. The authoritative list is the composition table in SOUP-DECLARATION.md, which apps/docs/src/soup.test.ts checks against the manifests on every run.

License

Apache-2.0. See LICENSE and NOTICE.

About

A self-hostable form engine, renderers and backend for React and Angular. One engine in browser and server, your design system's markup, Apache-2.0.

Topics

Resources

Contributing

Security policy

Stars

15 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages