@29decibel/formwc
v0.4.1
Published
A tiny JSON Schema form library built with Web Components and Lit.
Downloads
641
Readme
FormWC
FormWC is a small JSON Schema form library built with Web Components and Lit. It exposes a native custom element API, ships a minimal CSS-variable-driven theme, and supports custom widgets as ordinary custom elements.
flowchart TB
app["App / plain HTML page"] --> rendererEntry["@29decibel/formwc"]
app --> editorEntry["@29decibel/formwc/editor"]
app --> stimulusEntry["@29decibel/formwc/stimulus"]
rendererEntry --> defineRenderer["defineFormWC()"]
defineRenderer --> formElement["<json-schema-form>"]
stimulusEntry --> stimulusController["FormWCFormController"]
stimulusController --> formElement
editorEntry --> defineEditor["defineFormWCEditor()"]
defineEditor --> editorElement["<formwc-schema-editor>"]
editorElement --> draft["Serializable draft model"]
draft --> compiler["Editor compiler"]
compiler --> schema["JSON Schema"]
compiler --> uiSchema["UI schema"]
schema --> engine["Plain JS schema engine"]
uiSchema --> engine
engine --> formElement
formElement --> widgets["Custom widget elements"]
formElement --> events["form-change / form-submit events"]
formElement --> theme["CSS variable theme"]
fixtures["Matterflow fixture JSON"] --> editorElement
fixtures --> formElement
pkg["npm package"] --> cdn["jsDelivr / unpkg ESM"]
cdn --> rendererEntry
cdn --> editorEntry<script type="module">
import { defineFormWC } from "https://cdn.jsdelivr.net/npm/@29decibel/[email protected]/dist/formwc.js";
defineFormWC();
const form = document.querySelector("json-schema-form");
form.schema = {
type: "object",
properties: {
name: { type: "string", title: "Name" },
},
};
</script>
<json-schema-form></json-schema-form>Run locally:
pnpm install
pnpm devUseful checks:
pnpm test
pnpm buildThe local docs/demo page is http://127.0.0.1:5173/ when Vite is running. It loads the copied Matterflow fixture JSON from examples/matterflow-config and exercises conditionals, object pickers, repeatable groups, live form-data events, and CSS-variable theming.
Editor Mode
FormWC also has an optional editor entry for authoring schemas visually:
import { defineFormWCEditor } from "@29decibel/formwc/editor";
defineFormWCEditor();The editor custom element edits a serializable draft model and generates both JSON Schema and UI schema:
<formwc-schema-editor preview></formwc-schema-editor>Local examples:
http://127.0.0.1:5173/examples/editor-basic.htmlhttp://127.0.0.1:5173/examples/editor.html
CDN Usage
The pinned jsDelivr ESM endpoint for the current release is:
https://cdn.jsdelivr.net/npm/@29decibel/[email protected]/dist/formwc.jsUse pinned versions for production pages:
<script type="module">
import { defineFormWC } from "https://cdn.jsdelivr.net/npm/@29decibel/[email protected]/dist/formwc.js";
defineFormWC();
</script>
<json-schema-form></json-schema-form>The local CDN smoke-test page is available at http://127.0.0.1:5173/examples/jsdelivr.html when Vite is running. It intentionally imports FormWC from jsDelivr instead of the local source tree, so it is useful for checking that the published package works without a build step.
unpkg works too:
import { defineFormWC } from "https://unpkg.com/@29decibel/[email protected]/dist/formwc.js";The agent orientation file is published with the npm package:
https://cdn.jsdelivr.net/npm/@29decibel/[email protected]/llms.txtThe npm package is public so CDNs can serve it, but the published tarball is intentionally small: built dist files, README.md, llms.txt, and LICENSE.
Stimulus
Server-rendered apps can use the optional Stimulus controller:
import { Application } from "@hotwired/stimulus";
import { FormWCFormController } from "@29decibel/formwc/stimulus";
const application = Application.start();
application.register("formwc-form", FormWCFormController);<form
data-controller="formwc-form"
data-formwc-form-hide-submit-value="true"
data-formwc-form-omit-extra-data-value="true"
data-formwc-form-live-omit-value="onChange"
>
<script type="application/json" data-formwc-form-target="schema">
{ "type": "object", "properties": { "name": { "type": "string", "title": "Name" } } }
</script>
<script type="application/json" data-formwc-form-target="uiSchema">
{ "name": { "ui:placeholder": "Jane" } }
</script>
<input type="hidden" name="payload_json" data-formwc-form-target="payload" value='{"name":"Ada"}'>
<json-schema-form data-formwc-form-target="element"></json-schema-form>
<button type="submit">Save</button>
</form>The local Stimulus example is http://127.0.0.1:5173/examples/stimulus.html.
Rails
With a Rails JavaScript bundler, register the controller like any other Stimulus controller:
// app/javascript/controllers/formwc_form_controller.js
import { FormWCFormController } from "@29decibel/formwc/stimulus";
export default FormWCFormController;// app/javascript/controllers/index.js
import { application } from "./application";
import FormwcFormController from "./formwc_form_controller";
application.register("formwc-form", FormwcFormController);Then render JSON into inert script tags and keep the Rails hidden field as the submitted payload:
<%= form_with model: @response do |form| %>
<div
data-controller="formwc-form"
data-formwc-form-hide-submit-value="true"
data-formwc-form-omit-extra-data-value="true"
data-formwc-form-live-omit-value="onChange"
data-formwc-form-readonly-value="<%= @response.submitted? %>"
>
<script type="application/json" data-formwc-form-target="schema">
<%= raw @schema.to_json %>
</script>
<script type="application/json" data-formwc-form-target="uiSchema">
<%= raw @ui_schema.to_json %>
</script>
<script type="application/json" data-formwc-form-target="context">
<%= raw({ records: @records, recordDefinitions: @record_definitions }.to_json) %>
</script>
<%= form.hidden_field :payload_json,
value: @response.payload_json.to_json,
data: { formwc_form_target: "payload" } %>
<json-schema-form data-formwc-form-target="element"></json-schema-form>
</div>
<% unless @response.submitted? %>
<%= form.submit "Save" %>
<% end %>
<% end %>readonly keeps submitted responses visible while preventing edits. Text controls use native readonly behavior; select-style controls are disabled, and the hidden payload remains the canonical submitted value.
Releasing
Releases publish to npm through GitHub Actions when a version tag is pushed.
- Update
package.jsonversion. - Commit the version change.
- Create and push a matching tag:
git tag v0.4.1
git push origin main --tagsThe Release workflow verifies that the tag matches package.json, runs tests, builds dist/formwc.js, previews package contents, and publishes to npm.
The package uses npm Trusted Publishing for @29decibel/formwc and .github/workflows/release.yml, so no GitHub NPM_TOKEN secret is required.
