json-schema-form

repository·main·Indexed 41 days ago

https://github.com/remoteoss/json-schema-form

A headless UI library that converts JSON Schemas into JavaScript field definitions, enabling a single source of truth for form structures and validations across client and server environments. Version 1.2.18 is ESM-only and requires Node.js >= 18.14.0.

Tokens
6.3K
Snippets
19
Records
31
Agent score
97%

What's inside json-schema-form

  1. What is json-schema-form?

    main
    json-schema-form is a headless UI form library that uses JSON Schemas as the Single Source of Truth (SSoT). It transforms JSON schemas into JavaScript fields, allowing you to share data structures and validation logic between your backend and frontend, regardless of the programming language used. Because it is headless, it is designed to be easily consumed by various UI libraries.
  2. Migrate from v0 to v1

    main

    Upgrading from @remoteoss/json-schema-form v0 to v1 involves several breaking changes due to a complete TypeScript rewrite and a shift to an ESM-only architecture.

    Key Changes:

    • Environment: Requires Node.js >= 18.14.0. The package is now ESM-only (type: "module").
    • Dependencies: yup, lodash, and randexp have been removed. Only json-logic-js remains.
    • Validation: handleValidation no longer returns yupErrors; it only returns formErrors.
    • Field Properties: Use inputType instead of type for future-proofing.
    • Default Values: Defaults are now only applied when the initial value is exactly undefined. Falsy values like false, 0, '', or null are preserved and will not be replaced by the schema default.
    • Schema Modification: Property shorthands like presentation and errorMessage in the modify() function are removed. Use x-jsf-presentation and x-jsf-errorMessage instead.
    # Remove old version
    npm uninstall @remoteoss/json-schema-form
    
    # Install v1
    npm install @remoteoss/json-schema-form@v1
  3. Use x-jsf-presentation to customize field UI

    main

    You can use the x-jsf-presentation custom keyword within your JSON schema to override default UI behavior. Properties inside this object are merged into the resulting field object.

    Supported Overrides:

    • inputType: Manually specify the UI component type (e.g., text, email, date, checkbox, radio, select, file, number, fieldset, group-array).

    Example Schema:

    {
      "type": "string",
      "title": "User Email",
      "x-jsf-presentation": {
        "inputType": "email"
      }
    }
  4. Use legacyOptions for v0 validation compatibility

    main

    If your application relies on specific validation behaviors from v0 that were fixed in v1, you can re-enable them using the legacyOptions configuration in createHeadlessForm.

    Available legacy flags:

    • treatNullAsUndefined: (Default: false) When true, a null value is treated as undefined. This allows validation to succeed even if the schema type is not null.
    • allowForbiddenValues: (Default: false) When true, a value provided against a schema set to false will be allowed instead of returning a type error.
    const form = createHeadlessForm(schema, {
      legacyOptions: {
        treatNullAsUndefined: true,
        allowForbiddenValues: true
      }
    });
  5. Implement logic and validations with x-jsf-logic

    main

    The x-jsf-logic property enables advanced dynamic behavior using json-logic-js. It allows you to define both custom validations and computed values directly within the schema.

    Structure of x-jsf-logic

    • validations: A record where keys are identifiers and values contain:
      • rule: A RulesLogic object defining the validation logic.
      • errorMessage (optional): A custom string to display if the rule fails.
    • computedValues: A record where keys are identifiers and values contain:
      • rule: A RulesLogic object used to compute a value based on the current form state.

    Linking Logic to Schema

    To apply these rules to specific parts of the schema, use:

    • x-jsf-logic-validations: An array of strings referencing keys in the root validations object.
    • x-jsf-logic-computedAttrs: A record mapping keys to values, referencing computedValues in the root logic object to dynamically inject attributes.
  6. Handle validation errors with ValidationResult and FormErrors

    main

    When calling handleValidation, you receive a ValidationResult. If validation fails, the formErrors property will contain a FormErrors object.

    FormErrors Structure

    FormErrors is a recursive object where keys are field names and values are either:

    • A string (the error message).
    • A nested FormErrors object (for nested properties).
    • An Array<null | FormErrors> (for array/group-array fields).

    Custom Error Messages

    You can define custom error messages in your JSON schema using the x-jsf-errorMessage key, mapped to the specific validation type:

    {
      "type": "string",
      "x-jsf-errorMessage": {
        "required": "Please enter a username"
      }
    }
    // Example of the expected FormErrors shape
    const errors: FormErrors = {
      username: 'Required field',
      address: {
        street: 'The value must be a string'
      },
      items: [
        { name: 'Error in first item' }
      ]
    };
  7. Configure createHeadlessForm in v1

    main

    In v1, the configuration object for createHeadlessForm has changed. The customProperties option is deprecated and should be replaced by using the modify() function to update your schema before passing it to the form creator.

    New available options include:

    • initialValues: Object containing starting values.
    • legacyOptions: Object to opt-in to v0-style validation behaviors.
    • strictInputType: Boolean to enforce strict type checking.
    • disallowNewConditionalOptions: Boolean to enforce that conditional branches (if/then/else) can only narrow or re-label existing options (like enum or oneOf) rather than introducing new ones.
    const form = createHeadlessForm(schema, {
      initialValues: { username: '' },
      strictInputType: true,
      disallowNewConditionalOptions: true
    });
  8. Modify schema using x-jsf prefixes

    main

    The modify() function no longer supports the presentation and errorMessage property shorthands. To add presentation metadata or custom error messages to fields, use the x-jsf-presentation and x-jsf-errorMessage keys within the fields configuration.

    const { schema } = modify(originalSchema, {
      fields: {
        username: {
          "x-jsf-presentation": {
            placeholder: 'Enter username'
          },
          "x-jsf-errorMessage": {
            required: 'Important field'
          }
        }
      }
    });
    
    const form = createHeadlessForm(schema);
  9. Handle validation errors in v1

    main

    In v1, the handleValidation method returns a formErrors object. This object supports nested path access for complex schemas (e.g., formErrors?.address?.street). Note that yupErrors is no longer returned.

    const { handleValidation } = createHeadlessForm(schema);
    const { formErrors } = handleValidation(values);
    
    if (formErrors?.username) {
      console.log('Username error:', formErrors.username);
    }
    
    // For nested fields:
    if (formErrors?.address?.street) {
      console.log('Street validation failed');
    }
  10. Configure field presentation with x-jsf-presentation

    main

    Use the x-jsf-presentation property within a JsfSchema to control how a field is rendered in the UI. This allows you to specify input types, descriptions, and constraints like file size or date ranges.

    Supported keys include:

    • inputType: The FieldType used for rendering.
    • description: A string describing the field.
    • accept: A string defining accepted file types (for file inputs).
    • maxFileSize: A number defining the maximum allowed file size.
    • minDate: A string defining the minimum allowed date.
    • maxDate: A string defining the maximum allowed date.