Vanilla Schema Forms is a web-based application that dynamically generates HTML forms from a given JSON Schema. It is built using Vanilla TypeScript (no heavy frameworks) and Vite for a fast development experience.
- Dynamic Form Generation: Automatically creates HTML forms based on JSON Schema definitions.
- Hyperscript Rendering: Lightweight DOM generation using a hyperscript helper, avoiding innerHTML injection risks.
- Schema Dereferencing: Resolves
$refpointers within your JSON Schema using@apidevtools/json-schema-ref-parser. - Type-Safe Development: Written in TypeScript for robust and maintainable code.
- Modern Tooling: Utilizes Vite for development and bundling, providing a fast and efficient workflow.
- Customizable UI: Configurable field sorting, visibility, and text overrides via configuration files.
- Unit Testing: Includes tests for core parsing logic using Vitest.
Vanilla Schema Forms is in a very early pre-alpha state. I am not using it yet and it may not be working correctly for you.
The application follows a clear pipeline to transform a JSON Schema into an interactive form:
- Schema Loading: The
index.htmlfile (located in the project root) is the entry point. It loads the main application script (src/index.ts). - Schema Fetching & Parsing: The
src/index.tsscript fetches theschema.jsonfile. It then usessrc/parser.tsto parse this schema. - Schema Dereferencing and Transformation:
src/parser.tsutilizes the@apidevtools/json-schema-ref-parserlibrary to dereference any$refpointers in the JSON Schema. It then transforms the raw JSON Schema into a simplified, UI-friendlyFormNodetree structure. - Form Rendering:
src/index.tspasses theFormNodetree tosrc/renderer.ts. This orchestrator delegates the actual DOM creation tosrc/dom-renderer.ts, which produces the final HTML structure. - Live JSON Output: As the user interacts with the generated form, the application dynamically updates a live JSON output, reflecting the current state of the form data.
The application uses AJV (Another JSON Schema Validator) for robust, standard-compliant validation.
- Initialization: When a schema is parsed in
src/parser.ts, a bundled version (resolving external refs but keeping internal refs to avoid recursion issues) is passed tosrc/validator.ts. - Compilation:
src/validator.tsinitializes anAjv2020instance, registers standard formats (viaajv-formats) and custom formats (e.g.,uint64), and compiles the schema into a validation function. - Mapping: During rendering (
src/renderer.ts), the application builds a registry mapping AJV data paths (JSON pointers like/server/port) to HTML Element IDs. - Real-time Validation:
- When the user modifies the form, the current data is extracted from the DOM.
- The data is passed to the compiled AJV validator.
- If errors occur, they are mapped back to specific DOM elements using the registry, and error messages are displayed inline.
In addition to standard JSON Schema formats (email, date-time, etc.), the validator supports the following custom integer formats often found in systems like Protobuf or Go:
uint,uint8,uint16,uint32,uint64
.
├── index.html # Main HTML entry point
├── package.json # Project dependencies and scripts
├── schema.json # Example JSON Schema
├── tsconfig.json # TypeScript configuration
├── vite.config.ts # Vite configuration (including polyfills for Node.js modules)
└── src/
├── config.ts # Configuration for sorting, visibility, and heuristics
├── dom-renderer.ts # DOM generation logic using hyperscript
├── i18n.ts # Text overrides and internationalization mappings
├── index.ts # Main application logic, orchestrates parsing and rendering
├── form-data-reader.ts # Logic to read data back from the DOM
├── ui-schema-adapter.ts # Adapter for JSON Forms UI Schemas
├── parser.ts # Parses JSON Schema, dereferences, and transforms to FormNode tree
├── parser.test.ts # Unit tests for the parser
└── renderer.ts # Renders the FormNode tree into HTML form elements
- Install Dependencies:
npm install
- Development Server:
To start the development server and view the application in your browser:
The application will typically be available at
npm run dev
http://localhost:5173/(or a similar port if 5173 is in use).
- "Buffer is not defined" or "Module 'path' has been externalized" errors: This project uses Node.js polyfills via
vite-plugin-node-polyfillsto make@apidevtools/json-schema-ref-parsercompatible with browser environments. Ensure this plugin is correctly configured invite.config.tsandbufferandpathare included in itsincludeoption. - 404 errors for
index.html: Ensureindex.htmlis located in the root of your project directory.
You can group fields together (e.g., for horizontal layout) using the layout.groups configuration in src/config.ts.
import { setConfig } from "./config";
setConfig({
layout: {
groups: {
// Key is the ID of the parent object (usually the title)
"Connection": [
{
keys: ["host", "port"], // Fields to group
className: "d-flex gap-3", // CSS classes for the container
title: "Endpoint" // Optional title for the group
}
]
}
}
});If you prefer using a JSON Forms compatible UI Schema, you can use the built-in adapter.
import { adaptUiSchema } from "./ui-schema-adapter";
const uiSchema = {
type: "HorizontalLayout",
elements: [
{ type: "Control", scope: "#/properties/host" },
{ type: "Control", scope: "#/properties/port" }
]
};
// Applies the UI Schema to the object with ID "Connection"
adaptUiSchema(uiSchema, "Connection");This project uses Vitest for unit testing.