Skip to content

A JSON schema driven form generator supporting templates, ui json and i18n.

License

Notifications You must be signed in to change notification settings

marcomq/vanilla-schema-forms

Repository files navigation

Vanilla Schema Forms - A JSON schema driven form generator

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.

Features

  • 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 $ref pointers 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.

Status

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.

How it Works

The application follows a clear pipeline to transform a JSON Schema into an interactive form:

  1. Schema Loading: The index.html file (located in the project root) is the entry point. It loads the main application script (src/index.ts).
  2. Schema Fetching & Parsing: The src/index.ts script fetches the schema.json file. It then uses src/parser.ts to parse this schema.
  3. Schema Dereferencing and Transformation: src/parser.ts utilizes the @apidevtools/json-schema-ref-parser library to dereference any $ref pointers in the JSON Schema. It then transforms the raw JSON Schema into a simplified, UI-friendly FormNode tree structure.
  4. Form Rendering: src/index.ts passes the FormNode tree to src/renderer.ts. This orchestrator delegates the actual DOM creation to src/dom-renderer.ts, which produces the final HTML structure.
  5. 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.

Validation

The application uses AJV (Another JSON Schema Validator) for robust, standard-compliant validation.

Architecture

  1. 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 to src/validator.ts.
  2. Compilation: src/validator.ts initializes an Ajv2020 instance, registers standard formats (via ajv-formats) and custom formats (e.g., uint64), and compiles the schema into a validation function.
  3. Mapping: During rendering (src/renderer.ts), the application builds a registry mapping AJV data paths (JSON pointers like /server/port) to HTML Element IDs.
  4. 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.

Supported Formats

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

Project Structure

.
├── 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

Setup

  1. Install Dependencies:
    npm install
  2. Development Server: To start the development server and view the application in your browser:
    npm run dev
    The application will typically be available at http://localhost:5173/ (or a similar port if 5173 is in use).

Troubleshooting

  • "Buffer is not defined" or "Module 'path' has been externalized" errors: This project uses Node.js polyfills via vite-plugin-node-polyfills to make @apidevtools/json-schema-ref-parser compatible with browser environments. Ensure this plugin is correctly configured in vite.config.ts and buffer and path are included in its include option.
  • 404 errors for index.html: Ensure index.html is located in the root of your project directory.

Layout Grouping

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

JSON Forms Adapter

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");

Testing

This project uses Vitest for unit testing.

About

A JSON schema driven form generator supporting templates, ui json and i18n.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published