JSON Forms community - Latest posts https://jsonforms.discourse.group Latest posts Ajv-error not compatible with 3.7 Sure, i’ll be happy you put the reply here:)

]]>
https://jsonforms.discourse.group/t/ajv-error-not-compatible-with-3-7/2807#post_5 Mon, 16 Mar 2026 18:04:18 +0000 jsonforms.discourse.group-post-7064
Ajv-error not compatible with 3.7 Hi @clysss ,
sure you can. Note that I will post the solution here though and will mention essential facts (e.g. an installed package version).
If you can, pushing them to a small repo might be even better :slight_smile:
Best regards,
Lucas

]]>
https://jsonforms.discourse.group/t/ajv-error-not-compatible-with-3-7/2807#post_4 Mon, 16 Mar 2026 17:43:08 +0000 jsonforms.discourse.group-post-7063
Ajv-error not compatible with 3.7 Hello Lucas
,thanks a lot for your message,
Can I send you the files by email?.. including the package.json
Best regards

]]>
https://jsonforms.discourse.group/t/ajv-error-not-compatible-with-3-7/2807#post_3 Mon, 16 Mar 2026 16:42:15 +0000 jsonforms.discourse.group-post-7062
Ajv-error not compatible with 3.7 Hi @clysss , there should not have been an AJV update between 3.6 and 3.7 or at least not a major version one.
Effectively, 3.7.0 uses AJV 8.13.0.
Pre-release version 3.7.0-alpha.0 uses 8.18.0. This is recommended to be used as AJV belo 8.18 has a severe security flaw.

Can you give a whole example to execute and specify which version of ajv errors you use.
It could be worth checking if you updated the ajv errros version with updating to JSON Forms 3.7. Maybe that leads to unexpected behavior.

Best regards,
Lucas

]]>
https://jsonforms.discourse.group/t/ajv-error-not-compatible-with-3-7/2807#post_2 Mon, 16 Mar 2026 16:25:00 +0000 jsonforms.discourse.group-post-7061
Ajv-error not compatible with 3.7 I’m using customs ajv-errors.

after update from 3.6 to 3.7 the error messages are no more customs…

my main call looks like ;
<JsonForms

        //i18n={{translate: translator}}

        schema={schemasQuery.data.schema as JsonSchema}

        uischema={schemasQuery.data.uiSchema}

        data={isEmpty(jsonFormData) ? schemasQuery.data.data : jsonFormData}

        renderers={renderers}

        cells={materialCells}

        ajv={xcreateAjv()}

        validationMode="ValidateAndShow"

        onChange={({ data, errors }) => {

          setJsonFormData(data);

          setJsonFormErrors(errors);

        }}

and my ajv.ts containng the xcreateajv is :

import ajvErrors from ‘ajv-errors’;

import { createAjv } from ‘@jsonforms/core’;

const formats = {

email: {

type: 'string', 

validate: (data: string) => /^\[^\\s@\]+@\[^\\s@\]+\\.\[^\\s@\]+$/.test(data),

},

phone: {

type: 'string',

validate: (data: string) => /^\\+\[0-9\]+$/.test(data), 

},

url: {

type: 'string',

validate: (data: string) => /^https:\\/\\/.+/.test(data),

},

linkedin: {

type: 'string', 

validate: (data: string) => /^https:\\/\\/(www\\.)?linkedin\\.com\\/(in|company)\\/\[\\w-\]+\\/?$/.test(data),

},

// reconnaître le format SVG et arrêter les messages d’erreur //////////////////////DO NOT WORK as not in schema (in schemaui)

‘upload-logo’: {

validate: (str: string) => {

  return typeof str === 'string';

},

errorMessageKey: 'validation_svgInvalid',

errorMessage: "URL invalid - must begin with https://",

}

};

export const xcreateAjv = () => {

const myAjv=createAjv({

allErrors: true,

verbose: true,

$data: true, 

strict: false,

messages: true

});

ajvErrors(myAjv);

// Define the totalPercentage keyword

myAjv.addKeyword({

keyword: 'totalPercentage',

type: 'array',

validate: function (schema: any, data: any) {

  if (!Array.isArray(data)) return false; // Ensure data is an array

  const total = data.reduce((sum: number, entry: any) => sum + (entry.percent || 0), 0);

  return total === 100; // Check if total equals 100

},

errors: false, // Set to true if you want to use custom error messages

});

Object.entries(formats).forEach((\[name, format\]) => {

  myAjv.addFormat(name, format.validate);

});

return myAjv;

};

I tried with or without updating ajv package, both failed

which version of ajv should we use?

how should we write with new jsonforms?

Thx a lot!

]]>
https://jsonforms.discourse.group/t/ajv-error-not-compatible-with-3-7/2807#post_1 Wed, 11 Mar 2026 19:30:51 +0000 jsonforms.discourse.group-post-7060
Default placeholders in JsonSchema Hi @faridguzman91 ,
you can try setting your desired default value via the default property in the schema. Or did you already try this with

do it is with a custom generator function that extracts these values from the schema.json

E.g. in the schema

{
   "type": "string",
   "default": "mydefault"
}

Cheers,
Lucas

]]>
https://jsonforms.discourse.group/t/default-placeholders-in-jsonschema/2800#post_2 Tue, 17 Feb 2026 08:55:19 +0000 jsonforms.discourse.group-post-7053
Default placeholders in JsonSchema I would like to render a schema with these example values as placeholders in my custom inputfieldrenderer.vue renderer:

//yaml  
example:
        dns:
          a_record_targets:
            - 127.0.0.1
            - 127.0.0.1
          srv_record_targets_sip:
            - address: sip1-n1.example.com
              port: 5060
              priority: 1
              weight: 50
            - address: sip1-n2.example.com
              port: 5060
              priority: 1
              weight: 50
          srv_record_targets_sips:
            - address: sips.example.com
              port: 5061
              priority: 1
              weight: 100

The way i do it is with a custom generator function that extracts these values from the schema.json and sets the placeholders in the custom renderer, is there a built in option to do this? having to do this for every renderer is quite painful.

]]>
https://jsonforms.discourse.group/t/default-placeholders-in-jsonschema/2800#post_1 Wed, 11 Feb 2026 10:02:13 +0000 jsonforms.discourse.group-post-7052
Is the angular-material package dependency on hammerjs still needed? @thw0rted Thank you :slight_smile:

]]>
https://jsonforms.discourse.group/t/is-the-angular-material-package-dependency-on-hammerjs-still-needed/2799#post_4 Thu, 08 Jan 2026 08:24:48 +0000 jsonforms.discourse.group-post-7051
Is the angular-material package dependency on hammerjs still needed? Done! GitHub · Where software is built

]]>
https://jsonforms.discourse.group/t/is-the-angular-material-package-dependency-on-hammerjs-still-needed/2799#post_3 Wed, 07 Jan 2026 16:25:44 +0000 jsonforms.discourse.group-post-7050
Is the angular-material package dependency on hammerjs still needed? Hi @thw0rted ,
thanks for bringing this up. I agree that we should remove this dependency if we can do it without (greater) regressions.
I think it might have been introduced to support the deprecated HammerModule

Could you open an issue, please?

Thanks and best regards,
Lucas

]]>
https://jsonforms.discourse.group/t/is-the-angular-material-package-dependency-on-hammerjs-still-needed/2799#post_2 Wed, 07 Jan 2026 15:44:42 +0000 jsonforms.discourse.group-post-7049
Is the angular-material package dependency on hammerjs still needed? I didn’t want to open this as a “bug report” as such, but can file an issue if that’s appropriate.

When building a modern Angular application using the Angular Material JSONForms package, a warning is shown because it imports the hammerjs library – the bundler complains because the package is CJS-only. On investigation, it looks like this package hasn’t been updated in a decade, and many of the browser shortcomings it aimed to address are now implemented directly in the DOM.

As far as I can tell the package is imported once at the top of angular-material/src/library/index.ts and none of its helpers are directly used in the rest of the codebase. If I’m missing something please let me know, but otherwise it seems like this import (and the package dependency) could probably be safely removed.

]]>
https://jsonforms.discourse.group/t/is-the-angular-material-package-dependency-on-hammerjs-still-needed/2799#post_1 Tue, 30 Dec 2025 21:07:07 +0000 jsonforms.discourse.group-post-7048
Error on recursive schema: Maximum recursive updates exceeded in component <OneOfRenderer> Hi @fernandojsg,

We currently use AJV to determine the best element to show when we encounter a oneOf, however that only works if the oneOf is self-contained. If it isn’t the warning is shown and we just show the first one.

The max recursive error seems to indicate that we try to render an endlessly deep UI, which I would not have expected as the first element of the oneOf is actually the LEAF and even if we go down the branches, the rendering should stop at an empty array.

We need to check in more detail what is going wrong. Until then, feel free to debug why it tries to render endlessly deep. I would imagine something in the oneOf handling to go wrong.

]]>
https://jsonforms.discourse.group/t/error-on-recursive-schema-maximum-recursive-updates-exceeded-in-component-oneofrenderer/2798#post_2 Fri, 05 Dec 2025 16:44:20 +0000 jsonforms.discourse.group-post-7047
Error on recursive schema: Maximum recursive updates exceeded in component <OneOfRenderer> Hi everyone!
I’m working on a recursive schema that could have a leaf or a branch that could recursively have leaf/branch.
When I try to add a children I got a lot of logs from the AJV validator:

Combinator subschema is not self contained, can't hand it over to AJV

and after a while, it ends up throwing a max recursive error:

Uncaught (in promise) Maximum recursive updates exceeded in component . This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.

This is the JSON schema I’m using:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Configuration",
  "type": "object",
  "definitions": {
    "tree_leaf": {
      "type": "object",
      "properties": {
        "value": {
          "type": "string"
        },
        "label": {
          "description": "A human readable name (if left out the value will be title cased)",
          "type": "string"
        }
      },
      "required": ["value"],
      "additionalProperties": false
    },
    "tree_branch": {
      "type": "object",
      "properties": {
        "children": {
          "description": "Array of children. Either children or value needs to be provided",
          "$ref": "#/definitions/tree_options"
        },
        "label": {
          "description": "A human readable name (if left out the value will be title cased)",
          "type": "string"
        }
      },
      "required": ["children", "label"],
      "additionalProperties": false
    },
    "tree_options": {
      "type": "array",
      "uniqueItems": true,
      "items": {
        "oneOf": [
          {
            "title": "Leaf",
            "$ref": "#/definitions/tree_leaf"
          },
          {
            "title": "Branch",
            "$ref": "#/definitions/tree_branch"
          }
        ]
      }
    },
    "tree_picker": {
      "properties": {
        "values": {
          "$ref": "#/definitions/tree_options"
        }
      },
      "additionalProperties": false
    }
  },
  "properties": {
    "tree_picker": {
      "description": "Tree picker widget",
      "$ref": "#/definitions/tree_picker"
    }
  },
  "additionalProperties": false
}

Any help will be more than welcome! Thanks! :slight_smile:

]]>
https://jsonforms.discourse.group/t/error-on-recursive-schema-maximum-recursive-updates-exceeded-in-component-oneofrenderer/2798#post_1 Fri, 05 Dec 2025 00:26:06 +0000 jsonforms.discourse.group-post-7046
Error when testing JsonForms with vitest Hi @sdirix
Thanks for your reply and sorry for my delayed feedback.
As you suggested, I’m mocking the lodash/debounce in my tests to eliminate the timeout of debounce.
this is my mock:
vi.mock(‘lodash/debounce’, () => ({
default: (fn: (…args: any[]) => any) => {
const debounced = (…args: any[]) => {
fn(…args);
};
debounced.cancel = vi.fn();
debounced.flush = vi.fn();
return debounced;
},
}));

but still I get the ‘window is not defined’ error sometimes and only in the CI runs.

Do you have maybe a working example of such a mock for debounce?
Or a suggestion how to achieve such a mock that will work consistently?

]]>
https://jsonforms.discourse.group/t/error-when-testing-jsonforms-with-vitest/2796#post_3 Tue, 02 Dec 2025 07:27:27 +0000 jsonforms.discourse.group-post-7045
Issues with oneOf properties Hi @sdirix , I have tried loading the schema directly into JsonForms and get this error Uncaught MissingRefError: can’t resolve reference # from id #. JsonForms seems unable to handle the # self-reference

]]>
https://jsonforms.discourse.group/t/issues-with-oneof-properties/2793#post_7 Mon, 01 Dec 2025 00:28:43 +0000 jsonforms.discourse.group-post-7044
Async dynamic enum for autocomplete text field Thanks @lucas-koehler ,

Yes MaterialEnumControl is the component I want to customize.

I have already tried following the custom rendering guide - without success.

I’ll have a deeper look into it.

]]>
https://jsonforms.discourse.group/t/async-dynamic-enum-for-autocomplete-text-field/2787#post_3 Thu, 27 Nov 2025 09:37:02 +0000 jsonforms.discourse.group-post-7043
HandleChange in Custom Array Renderer (Vue) Hi @FOppici,

You can always inject the raw JSON Forms building blocks and thereby recreate handleChange for your use case, e.g.

You can inject the form-wide dispatch:

const dispatch = inject<Dispatch>(‘dispatch’);

Dispatch works on actions, so you can import Actions from @jsonforms/core , create the UPDATE action yourself and dispatch it.

Alternatively you can reuse one of the core helpers, e.g.

const { handleChange } = mapDispatchToControlProps(dispatch);
]]>
https://jsonforms.discourse.group/t/handlechange-in-custom-array-renderer-vue/2797#post_2 Tue, 25 Nov 2025 16:21:36 +0000 jsonforms.discourse.group-post-7042
HandleChange in Custom Array Renderer (Vue) Hi all. I’ve integrated JsonForms in a Vue 3 app.
I created a custom renderer for arrays. in this renderer I include an autocomplete listing different objects and I’d like to populate fields of an array item based on autocomplete selection.

Unfortunately, seems that the useJsonFormsArrayControl() method I’m using doesn’t expose the handleChange method, so I’m at a loss on how to change form status.

Worth noting I’m using the Composition API style of component definition for styling rules reasons…

<script setup lang="ts">

import { DispatchRenderer, useJsonFormsArrayControl, type RendererProps } from '@jsonforms/vue';
import { type ControlProps } from '@jsonforms/vue';


const props = defineProps<RendererProps<ControlProps>>();
const  ctrl = useJsonFormsArrayControl(props);
]]>
https://jsonforms.discourse.group/t/handlechange-in-custom-array-renderer-vue/2797#post_1 Tue, 25 Nov 2025 15:28:40 +0000 jsonforms.discourse.group-post-7041
Error when testing JsonForms with vitest Hi @YuriSapiens,

I think you have multiple options available:

The debounce in the JSON Forms component is 10ms long, so you could wait in each test for that amount of time.

You could setup your tests to resolve lodash/debounce to your own implementation which then just applies the function immediately without debouncing.

You could run JSON Forms in a controlled style. Then you don’t need to use onChange at all and therefore don’t need to care about that it is debounced.

]]>
https://jsonforms.discourse.group/t/error-when-testing-jsonforms-with-vitest/2796#post_2 Tue, 25 Nov 2025 09:37:07 +0000 jsonforms.discourse.group-post-7040
Error when testing JsonForms with vitest Full error stack trace

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Unhandled Errors ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
Vitest caught 1 unhandled error during the test run.
This might cause false positive tests. Resolve unhandled errors to make sure your tests are not affected.
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Uncaught Exception ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
ReferenceError: window is not defined
❯ getCurrentEventPriority ../../node_modules/react-dom/cjs/react-dom.development.js:10993:22
❯ requestUpdateLane ../../node_modules/react-dom/cjs/react-dom.development.js:25495:19
❯ dispatchSetState ../../node_modules/react-dom/cjs/react-dom.development.js:16648:14
❯ Object.onChange [as current] src/lib/preview/Preview.tsx:109:13
107| cells={uiTypesCustomCells}
108| onChange={(event) => {
109| setData(event.data);
| ^
110| onFormDataChange?.(simplifyEventStructure(event));
111| }}
❯ ../../node_modules/@jsonforms/react/src/JsonFormsContext.tsx:260:59
❯ invokeFunc ../../node_modules/lodash/debounce.js:95:19
❯ trailingEdge ../../node_modules/lodash/debounce.js:144:14
❯ Timeout.timerExpired [as _onTimeout] ../../node_modules/lodash/debounce.js:132:14
❯ listOnTimeout node:internal/timers:588:17
❯ processTimers node:internal/timers:523:7
This error originated in “src/lib/preview/tests/errorMessages.test.tsx” test file. It doesn’t mean the error was thrown inside the file itself, but while it was running.
This error was caught after test environment was torn down. Make sure to cancel any running tasks before test finishes:

  • cancel timeouts using clearTimeout and clearInterval
  • wait for promises to resolve using the await keyword
    ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯

Hello,
I’m using @jsonforms/[email protected]
I’m writing unit tests with vitest that render JsonForms.
When I run the test I sometimes get the error:
ReferenceError: window is not defined (see full error above)
It’s caused by a timing issue of the lodash debounce that is used inside JsonForms.
The questions is what’s the proper way to mock the JsonForms debounce in my tests so it will run immediately and won’t cause timing issue.

]]>
https://jsonforms.discourse.group/t/error-when-testing-jsonforms-with-vitest/2796#post_1 Tue, 25 Nov 2025 09:25:33 +0000 jsonforms.discourse.group-post-7039
Hiding a specific path when rendering a complex oneOf Hi @travjenkins ,

yes the scope property is used to reference the property to render. Thus, it’s last segment always is the property itself as long as your UI Schema is configured correctly.

Best regards,
Lucas

]]>
https://jsonforms.discourse.group/t/hiding-a-specific-path-when-rendering-a-complex-oneof/2795#post_2 Tue, 25 Nov 2025 08:44:55 +0000 jsonforms.discourse.group-post-7038
Issues with oneOf properties Hi @SilentArctic,

Did you try JSON Forms without invoking json-schema-ref-parser? I think the schema in question should be supported out of the box.

]]>
https://jsonforms.discourse.group/t/issues-with-oneof-properties/2793#post_6 Tue, 25 Nov 2025 08:28:17 +0000 jsonforms.discourse.group-post-7037
Hiding a specific path when rendering a complex oneOf TL;DR - is it safe to assume that the element scope can be parsed to find the property that is being rendered?

I have a custom renderer that renders a oneOf with a discriminator. The renderer ( ui/src/forms/overrides/material/complex/MaterialOneOfRenderer_Discriminator.tsx at main · estuary/ui · GitHub ) is a copy/paste/tweak of the MaterialOneOfRenderer from y’all.

In our custom version I am calling createCombinatorRenderInfos to get back oneOfRenderInfos and then filtering out the discriminator property from the UISchema’s elements property.

    oneOfRenderInfos.map((renderer) => {
        const { uischema: rendererUischema } = renderer as any;
        rendererUischema.elements = rendererUischema.elements.filter(
            (el: any) => {
                const pathSegments = el.scope?.split('/');
                if (pathSegments && pathSegments.length > 0) {
                    const lastSegment = decode(
                        pathSegments[pathSegments.length - 1]
                    );
                    return lastSegment !== discriminatorProperty;
                }

                return true;
            }
        );

        return renderer;
    });

This feels safe - but wanted to check that it is. Will the ending of the scope property normally be the name of a property? So far in my testing that seems right and looking are your code (like how deriveLabel does something similar) it seems this is how y’all find properties already but wanted to check.

]]>
https://jsonforms.discourse.group/t/hiding-a-specific-path-when-rendering-a-complex-oneof/2795#post_1 Mon, 24 Nov 2025 23:25:01 +0000 jsonforms.discourse.group-post-7036
Issues with oneOf properties Thanks for looking into the boolean/array problem! I have created an issue.

As for the previous problem, I believe the root cause was a circular reference in my schema (one of my oneOf properties has a $ref to itself for allowing multiple layers of paragraphs). I’d love a built-in way to limit circular reference depth, but for the time being I am intercepting the json-schema-ref-parser deref and replacing the subschema with a simple array of strings. I’ll provide a snippet of my schema below so you have a better view of what I’m working with, but I understand limited circular refs is likely a low priority.

Thanks for your time!

{
"type": "array",
   "items": {
      "oneOf": [
         {
            "title": "String",
            "type": "string"
         },

         {
            "title": "Advanced Text",
            "type": "object",
            "properties": {
               "type": {
                  "type": "string",
                  "enum": [
                     "text",
                     "sidebar",
                     "example",
                     "read-aloud",
                     "codeblock"
                  ]
               },
               "title": {
                  "type": "string"
               },
               "forceTitleLevel": {
                  "type": "integer"
               },
               "page": {
                  "type": "integer"
               },
               "entries": { "$ref": "#" } // this is the problem
            },
            "required": [
               "entries"
            ],
            "additionalProperties": false
         },
      ]
   }
}
]]>
https://jsonforms.discourse.group/t/issues-with-oneof-properties/2793#post_5 Mon, 24 Nov 2025 17:26:53 +0000 jsonforms.discourse.group-post-7035
Issues with oneOf properties Hi @SilentArctic ,

thanks for working on this.

I am not aware of the independent AJV being a problem but I have also not done it, yet. Is your installed AJV of a compatible version? Otherwise, I could imagine this leading to problems.

The bug with the switch boolean ↔ array I can reproduce. Would you like to open an issue for this at https://github.com/eclipsesource/jsonforms/issues ?

Thanks and best regards,
Lucas

]]>
https://jsonforms.discourse.group/t/issues-with-oneof-properties/2793#post_4 Mon, 24 Nov 2025 11:57:21 +0000 jsonforms.discourse.group-post-7034
Release v3.7.0? Hi @Doug348 ,

the 3.7.0 release is currently planned for end of this week, latest next week.

Best regards,
Lucas

]]>
https://jsonforms.discourse.group/t/release-v3-7-0/2794#post_2 Mon, 24 Nov 2025 11:14:18 +0000 jsonforms.discourse.group-post-7033
Release v3.7.0? Hello JSON Forms team,

Do you have an anticipated date or timeframe for publishing the official v3.7.0 release? I see there are a few alpha tags in Github.

Thank you for all your great work!

Doug

]]>
https://jsonforms.discourse.group/t/release-v3-7-0/2794#post_1 Tue, 18 Nov 2025 21:54:21 +0000 jsonforms.discourse.group-post-7032
Issues with oneOf properties Sure, I’ll get on that. If it matters I also have AJV installed independently for other validation purposes, is it possible that could be interfering?

While I’m working out a reproducible demo, I’ve noticed another issue with oneOf. In the example above, the options are a boolean value or an array of strings.

- If I switch from the array to the boolean I am prompted to clear the data in order to proceed.

  • If I then switch from the boolean to the array, no prompt happens
    • When I try to add an array value I get a console error
    • TypeError: array.push is not a function
    • I have verified that this is because it’s trying to push a new array value onto the old boolean value

I will include this example in my reproduction, but is easy to replicate by copying the data above if you want to take a look before I get mine up.

]]>
https://jsonforms.discourse.group/t/issues-with-oneof-properties/2793#post_3 Tue, 18 Nov 2025 16:33:58 +0000 jsonforms.discourse.group-post-7031
Issues with oneOf properties Hi @SilentArctic

Unfortunately, I cannot reproduce the error message in the JSON Forms Vue Seed.

Can you provide an example repository or or JSBin or similar where this can be reproduced?

Best regards,
Lucas

]]>
https://jsonforms.discourse.group/t/issues-with-oneof-properties/2793#post_2 Tue, 18 Nov 2025 09:38:33 +0000 jsonforms.discourse.group-post-7030
Should JSON Forms core distinguish between readonly and disabled controls? Hi @kchobantonov ,
I agree that it would be good to be able to distinguish between the two. There is already an issue in the JSON Forms repository: Allow custom renderers to handle the readonly behaviour. · Issue #2479 · eclipsesource/jsonforms · GitHub

Feel free to add your ideas there and/or contribute the featues. If you want to contribute, it probably makes sense to outline your approach in the issue so it can be discussed there :slight_smile:

Thanks and best regards,
Lucas

]]>
https://jsonforms.discourse.group/t/should-json-forms-core-distinguish-between-readonly-and-disabled-controls/2791#post_2 Tue, 18 Nov 2025 08:57:16 +0000 jsonforms.discourse.group-post-7029
Issues with oneOf properties Hello! I’m having an issue with oneOf groups. It technically works but the console logs this error message as soon as the oneOf is rendered. This happens for every oneOf property, and I’d like to prevent these errors from happening. Any help would be appreciated

@jsonforms/core: 3.6.0
@jsonforms/vue: 3.6.0
@jsonforms/vue-vanilla: 3.6.0

SCHEMA

{
    "type": "array",
    "items": {
      "type": "object",
      "properties": {
         "name": {
            "type": "string"
         },
         "page": {
            "type": "integer"
         },
         "prerequisites": {
            "oneOf": [
               {
                  "title": "True/False",
                  "type": "boolean"
               },
               {
                  "title": "Named Prereqs",
                  "type": "array",
                  "items": {
                     "type": "string"
                  }
               }
            ]
         }
     }
}

UI SCHEMA

{
   "type": "VerticalLayout",
   "elements": [
      {
         "type": "Group",
         "label": "Talent",
         "elements": [
            {
               "type": "Control",
               "scope": "#/properties/name"
            },
            {
               "type": "Control",
               "scope": "#/properties/page"
            },
            {
               "type": "Control",
               "scope": "#/properties/prerequisites"
            }
         ]
      }
   ]
}

ERROR MESSAGE

const schema0 = scope.schema[0];const schema1 = scope.schema[1];const schema1 = scope.schema[1];const schema7 = scope.schema[4];const schema7 = scope.schema[4];const schema9 = scope.schema[5];const schema9 = scope.schema[5];const validate1 = scope.validate[0];const validate3 = scope.validate[1];const func0 = scope.func[0];const func0 = scope.func[0];return function validate0(data, {instancePath="", parentData, parentDataProperty, rootData=data}={}){let vErrors = null;let errors = 0;if((!(data && typeof data == "object" && !Array.isArray(data))) && (typeof data !== "boolean")){const err0 = {instancePath,schemaPath:"#/type",keyword:"type",params:{type: schema0.type},message:"must be object,boolean",schema:schema0.type,parentSchema:schema0,data};if(vErrors === null){vErrors = [err0];}else {vErrors.push(err0);}errors++;}if(data && typeof data == "object" && !Array.isArray(data)){if(data.$id !== undefined){let data0 = data.$id;if(!(typeof data0 === "string")){const err1 = {instancePath:instancePath+"/$id",schemaPath:"#/properties/%24id/type",keyword:"type",params:{type: "string"},message:"must be string",schema:schema0.properties.$id.type,parentSchema:schema0.properties.$id,data:data0};if(vErrors === null){vErrors = [err1];}else {vErrors.push(err1);}errors++;}}if(data.$schema !== undefined){let data1 = data.$schema;if(!(typeof data1 === "string")){const err2 = {instancePath:instancePath+"/$schema",schemaPath:"#/properties/%24schema/type",keyword:"type",params:{type: "string"},message:"must be string",schema:schema0.properties.$schema.type,parentSchema:schema0.properties.$schema,data:data1};if(vErrors === null){vErrors = [err2];}else {vErrors.push(err2);}errors++;}}if(data.$ref !== undefined){let data2 = data.$ref;if(!(typeof data2 === "string")){const err3 = {instancePath:instancePath+"/$ref",schemaPath:"#/properties/%24ref/type",keyword:"type",params:{type: "string"},message:"must be string",schema:schema0.properties.$ref.type,parentSchema:schema0.properties.$ref,data:data2};if(vErrors === null){vErrors = [err3];}else {vErrors.push(err3);}errors++;}}if(data.$comment !== undefined){let data3 = data.$comment;if(typeof data3 !== "string"){const err4 = {instancePath:instancePath+"/$comment",schemaPath:"#/properties/%24comment/type",keyword:"type",params:{type: "string"},message:"must be string",schema:schema0.properties.$comment.type,parentSchema:schema0.properties.$comment,data:data3};if(vErrors === null){vErrors = [err4];}else {vErrors.push(err4);}errors++;}}if(data.title !== undefined){let data4 = data.title;if(typeof data4 !== "string"){const err5 = {instancePath:instancePath+"/title",schemaPath:"#/properties/title/type",keyword:"type",params:{type: "string"},message:"must be string",schema:schema0.properties.title.type,parentSchema:schema0.properties.title,data:data4};if(vErrors === null){vErrors = [err5];}else {vErrors.push(err5);}errors++;}}if(data.description !== undefined){let data5 = data.description;if(typeof data5 !== "string"){const err6 = {instancePath:instancePath+"/description",schemaPath:"#/properties/description/type",keyword:"type",params:{type: "string"},message:"must be string",schema:schema0.properties.description.type,parentSchema:schema0.properties.description,data:data5};if(vErrors === null){vErrors = [err6];}else {vErrors.push(err6);}errors++;}}if(data.readOnly !== undefined){let data6 = data.readOnly;if(typeof data6 !== "boolean"){const err7 = {instancePath:instancePath+"/readOnly",schemaPath:"#/properties/readOnly/type",keyword:"type",params:{type: "boolean"},message:"must be boolean",schema:schema0.properties.readOnly.type,parentSchema:schema0.properties.readOnly,data:data6};if(vErrors === null){vErrors = [err7];}else {vErrors.push(err7);}errors++;}}if(data.examples !== undefined){let data7 = data.examples;if(!(Array.isArray(data7))){const err8 = {instancePath:instancePath+"/examples",schemaPath:"#/properties/examples/type",keyword:"type",params:{type: "array"},message:"must be array",schema:schema0.properties.examples.type,parentSchema:schema0.properties.examples,data:data7};if(vErrors === null){vErrors = [err8];}else {vErrors.push(err8);}errors++;}}if(data.multipleOf !== undefined){let data8 = data.multipleOf;if(typeof data8 == "number"){if(data8 <= 0 || isNaN(data8)){const err9 = {instancePath:instancePath+"/multipleOf",schemaPath:"#/properties/multipleOf/exclusiveMinimum",keyword:"exclusiveMinimum",params:{comparison: ">", limit: 0},message:"must be > 0",schema:0,parentSchema:schema0.properties.multipleOf,data:data8};if(vErrors === null){vErrors = [err9];}else {vErrors.push(err9);}errors++;}}else {const err10 = {instancePath:instancePath+"/multipleOf",schemaPath:"#/properties/multipleOf/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema0.properties.multipleOf.type,parentSchema:schema0.properties.multipleOf,data:data8};if(vErrors === null){vErrors = [err10];}else {vErrors.push(err10);}errors++;}}if(data.maximum !== undefined){let data9 = data.maximum;if(!(typeof data9 == "number")){const err11 = {instancePath:instancePath+"/maximum",schemaPath:"#/properties/maximum/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema0.properties.maximum.type,parentSchema:schema0.properties.maximum,data:data9};if(vErrors === null){vErrors = [err11];}else {vErrors.push(err11);}errors++;}}if(data.exclusiveMaximum !== undefined){let data10 = data.exclusiveMaximum;if(!(typeof data10 == "number")){const err12 = {instancePath:instancePath+"/exclusiveMaximum",schemaPath:"#/properties/exclusiveMaximum/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema0.properties.exclusiveMaximum.type,parentSchema:schema0.properties.exclusiveMaximum,data:data10};if(vErrors === null){vErrors = [err12];}else {vErrors.push(err12);}errors++;}}if(data.minimum !== undefined){let data11 = data.minimum;if(!(typeof data11 == "number")){const err13 = {instancePath:instancePath+"/minimum",schemaPath:"#/properties/minimum/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema0.properties.minimum.type,parentSchema:schema0.properties.minimum,data:data11};if(vErrors === null){vErrors = [err13];}else {vErrors.push(err13);}errors++;}}if(data.exclusiveMinimum !== undefined){let data12 = data.exclusiveMinimum;if(!(typeof data12 == "number")){const err14 = {instancePath:instancePath+"/exclusiveMinimum",schemaPath:"#/properties/exclusiveMinimum/type",keyword:"type",params:{type: "number"},message:"must be number",schema:schema0.properties.exclusiveMinimum.type,parentSchema:schema0.properties.exclusiveMinimum,data:data12};if(vErrors === null){vErrors = [err14];}else {vErrors.push(err14);}errors++;}}if(data.maxLength !== undefined){let data13 = data.maxLength;if(!((typeof data13 == "number") && (!(data13 % 1) && !isNaN(data13)))){const err15 = {instancePath:instancePath+"/maxLength",schemaPath:"#/definitions/nonNegativeInteger/type",keyword:"type",params:{type: "integer"},message:"must be integer",schema:schema1.type,parentSchema:schema1,data:data13};if(vErrors === null){vErrors = [err15];}else {vErrors.push(err15);}errors++;}if(typeof data13 == "number"){if(data13 < 0 || isNaN(data13)){const err16 = {instancePath:instancePath+"/maxLength",schemaPath:"#/definitions/nonNegativeInteger/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0",schema:0,parentSchema:schema1,data:data13};if(vErrors === null){vErrors = [err16];}else {vErrors.push(err16);}errors++;}}}if(data.minLength !== undefined){if(!(validate1(data.minLength, {instancePath:instancePath+"/minLength",parentData:data,parentDataProperty:"minLength",rootData}))){vErrors = vErrors === null ? validate1.errors : vErrors.concat(validate1.errors);errors = vErrors.length;}}if(data.pattern !== undefined){let data15 = data.pattern;if(!(typeof data15 === "string")){const err17 = {instancePath:instancePath+"/pattern",schemaPath:"#/properties/pattern/type",keyword:"type",params:{type: "string"},message:"must be string",schema:schema0.properties.pattern.type,parentSchema:schema0.properties.pattern,data:data15};if(vErrors === null){vErrors = [err17];}else {vErrors.push(err17);}errors++;}}if(data.additionalItems !== undefined){if(!(validate0(data.additionalItems, {instancePath:instancePath+"/additionalItems",parentData:data,parentDataProperty:"additionalItems",rootData}))){vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);errors = vErrors.length;}}if(data.items !== undefined){let data17 = data.items;const _errs35 = errors;let valid2 = false;const _errs36 = errors;if(!(validate0(data17, {instancePath:instancePath+"/items",parentData:data,parentDataProperty:"items",rootData}))){vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);errors = vErrors.length;}var _valid0 = _errs36 === errors;valid2 = valid2 || _valid0;if(!valid2){const _errs37 = errors;if(!(validate3(data17, {instancePath:instancePath+"/items",parentData:data,parentDataProperty:"items",rootData}))){vErrors = vErrors === null ? validate3.errors : vErrors.concat(validate3.errors);errors = vErrors.length;}var _valid0 = _errs37 === errors;valid2 = valid2 || _valid0;}if(!valid2){const err18 = {instancePath:instancePath+"/items",schemaPath:"#/properties/items/anyOf",keyword:"anyOf",params:{},message:"must match a schema in anyOf",schema:schema0.properties.items.anyOf,parentSchema:schema0.properties.items,data:data17};if(vErrors === null){vErrors = [err18];}else {vErrors.push(err18);}errors++;}else {errors = _errs35;if(vErrors !== null){if(_errs35){vErrors.length = _errs35;}else {vErrors = null;}}}}if(data.maxItems !== undefined){let data18 = data.maxItems;if(!((typeof data18 == "number") && (!(data18 % 1) && !isNaN(data18)))){const err19 = {instancePath:instancePath+"/maxItems",schemaPath:"#/definitions/nonNegativeInteger/type",keyword:"type",params:{type: "integer"},message:"must be integer",schema:schema1.type,parentSchema:schema1,data:data18};if(vErrors === null){vErrors = [err19];}else {vErrors.push(err19);}errors++;}if(typeof data18 == "number"){if(data18 < 0 || isNaN(data18)){const err20 = {instancePath:instancePath+"/maxItems",schemaPath:"#/definitions/nonNegativeInteger/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0",schema:0,parentSchema:schema1,data:data18};if(vErrors === null){vErrors = [err20];}else {vErrors.push(err20);}errors++;}}}if(data.minItems !== undefined){if(!(validate1(data.minItems, {instancePath:instancePath+"/minItems",parentData:data,parentDataProperty:"minItems",rootData}))){vErrors = vErrors === null ? validate1.errors : vErrors.concat(validate1.errors);errors = vErrors.length;}}if(data.uniqueItems !== undefined){let data20 = data.uniqueItems;if(typeof data20 !== "boolean"){const err21 = {instancePath:instancePath+"/uniqueItems",schemaPath:"#/properties/uniqueItems/type",keyword:"type",params:{type: "boolean"},message:"must be boolean",schema:schema0.properties.uniqueItems.type,parentSchema:schema0.properties.uniqueItems,data:data20};if(vErrors === null){vErrors = [err21];}else {vErrors.push(err21);}errors++;}}if(data.contains !== undefined){if(!(validate0(data.contains, {instancePath:instancePath+"/contains",parentData:data,parentDataProperty:"contains",rootData}))){vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);errors = vErrors.length;}}if(data.maxProperties !== undefined){let data22 = data.maxProperties;if(!((typeof data22 == "number") && (!(data22 % 1) && !isNaN(data22)))){const err22 = {instancePath:instancePath+"/maxProperties",schemaPath:"#/definitions/nonNegativeInteger/type",keyword:"type",params:{type: "integer"},message:"must be integer",schema:schema1.type,parentSchema:schema1,data:data22};if(vErrors === null){vErrors = [err22];}else {vErrors.push(err22);}errors++;}if(typeof data22 == "number"){if(data22 < 0 || isNaN(data22)){const err23 = {instancePath:instancePath+"/maxProperties",schemaPath:"#/definitions/nonNegativeInteger/minimum",keyword:"minimum",params:{comparison: ">=", limit: 0},message:"must be >= 0",schema:0,parentSchema:schema1,data:data22};if(vErrors === null){vErrors = [err23];}else {vErrors.push(err23);}errors++;}}}if(data.minProperties !== undefined){if(!(validate1(data.minProperties, {instancePath:instancePath+"/minProperties",parentData:data,parentDataProperty:"minProperties",rootData}))){vErrors = vErrors === null ? validate1.errors : vErrors.concat(validate1.errors);errors = vErrors.length;}}if(data.required !== undefined){let data24 = data.required;if(Array.isArray(data24)){const len0 = data24.length;for(let i0=0; i0<len0; i0++){let data25 = data24[i0];if(typeof data25 !== "string"){const err24 = {instancePath:instancePath+"/required/" + i0,schemaPath:"#/definitions/stringArray/items/type",keyword:"type",params:{type: "string"},message:"must be string",schema:schema7.items.type,parentSchema:schema7.items,data:data25};if(vErrors === null){vErrors = [err24];}else {vErrors.push(err24);}errors++;}}let i1 = data24.length;let j0;if(i1 > 1){const indices0 = {};for(;i1--;){let item0 = data24[i1];if(typeof item0 !== "string"){continue;}if(typeof indices0[item0] == "number"){j0 = indices0[item0];const err25 = {instancePath:instancePath+"/required",schemaPath:"#/definitions/stringArray/uniqueItems",keyword:"uniqueItems",params:{i: i1, j: j0},message:"must NOT have duplicate items (items ## "+j0+" and "+i1+" are identical)",schema:true,parentSchema:schema7,data:data24};if(vErrors === null){vErrors = [err25];}else {vErrors.push(err25);}errors++;break;}indices0[item0] = i1;}}}else {const err26 = {instancePath:instancePath+"/required",schemaPath:"#/definitions/stringArray/type",keyword:"type",params:{type: "array"},message:"must be array",schema:schema7.type,parentSchema:schema7,data:data24};if(vErrors === null){vErrors = [err26];}else {vErrors.push(err26);}errors++;}}if(data.additionalProperties !== undefined){if(!(validate0(data.additionalProperties, {instancePath:instancePath+"/additionalProperties",parentData:data,parentDataProperty:"additionalProperties",rootData}))){vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);errors = vErrors.length;}}if(data.definitions !== undefined){let data27 = data.definitions;if(data27 && typeof data27 == "object" && !Array.isArray(data27)){for(const key0 in data27){if(!(validate0(data27[key0], {instancePath:instancePath+"/definitions/" + key0.replace(/~/g, "~0").replace(/\//g, "~1"),parentData:data27,parentDataProperty:key0,rootData}))){vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);errors = vErrors.length;}}}else {const err27 = {instancePath:instancePath+"/definitions",schemaPath:"#/properties/definitions/type",keyword:"type",params:{type: "object"},message:"must be object",schema:schema0.properties.definitions.type,parentSchema:schema0.properties.definitions,data:data27};if(vErrors === null){vErrors = [err27];}else {vErrors.push(err27);}errors++;}}if(data.properties !== undefined){let data29 = data.properties;if(data29 && typeof data29 == "object" && !Array.isArray(data29)){for(const key1 in data29){if(!(validate0(data29[key1], {instancePath:instancePath+"/properties/" + key1.replace(/~/g, "~0").replace(/\//g, "~1"),parentData:data29,parentDataProperty:key1,rootData}))){vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);errors = vErrors.length;}}}else {const err28 = {instancePath:instancePath+"/properties",schemaPath:"#/properties/properties/type",keyword:"type",params:{type: "object"},message:"must be object",schema:schema0.properties.properties.type,parentSchema:schema0.properties.properties,data:data29};if(vErrors === null){vErrors = [err28];}else {vErrors.push(err28);}errors++;}}if(data.patternProperties !== undefined){let data31 = data.patternProperties;if(data31 && typeof data31 == "object" && !Array.isArray(data31)){for(const key2 in data31){const _errs65 = errors;var valid11 = _errs65 === errors;if(!valid11){const err29 = {instancePath:instancePath+"/patternProperties",schemaPath:"#/properties/patternProperties/propertyNames",keyword:"propertyNames",params:{propertyName: key2},message:"property name must be valid",schema:schema0.properties.patternProperties.propertyNames,parentSchema:schema0.properties.patternProperties,data:data31};if(vErrors === null){vErrors = [err29];}else {vErrors.push(err29);}errors++;}}for(const key3 in data31){if(!(validate0(data31[key3], {instancePath:instancePath+"/patternProperties/" + key3.replace(/~/g, "~0").replace(/\//g, "~1"),parentData:data31,parentDataProperty:key3,rootData}))){vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);errors = vErrors.length;}}}else {const err30 = {instancePath:instancePath+"/patternProperties",schemaPath:"#/properties/patternProperties/type",keyword:"type",params:{type: "object"},message:"must be object",schema:schema0.properties.patternProperties.type,parentSchema:schema0.properties.patternProperties,data:data31};if(vErrors === null){vErrors = [err30];}else {vErrors.push(err30);}errors++;}}if(data.dependencies !== undefined){let data33 = data.dependencies;if(data33 && typeof data33 == "object" && !Array.isArray(data33)){for(const key4 in data33){let data34 = data33[key4];const _errs72 = errors;let valid14 = false;const _errs73 = errors;if(!(validate0(data34, {instancePath:instancePath+"/dependencies/" + key4.replace(/~/g, "~0").replace(/\//g, "~1"),parentData:data33,parentDataProperty:key4,rootData}))){vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);errors = vErrors.length;}var _valid1 = _errs73 === errors;valid14 = valid14 || _valid1;if(!valid14){const _errs74 = errors;if(Array.isArray(data34)){const len1 = data34.length;for(let i2=0; i2<len1; i2++){let data35 = data34[i2];if(typeof data35 !== "string"){const err31 = {instancePath:instancePath+"/dependencies/" + key4.replace(/~/g, "~0").replace(/\//g, "~1")+"/" + i2,schemaPath:"#/definitions/stringArray/items/type",keyword:"type",params:{type: "string"},message:"must be string",schema:schema7.items.type,parentSchema:schema7.items,data:data35};if(vErrors === null){vErrors = [err31];}else {vErrors.push(err31);}errors++;}}let i3 = data34.length;let j1;if(i3 > 1){const indices1 = {};for(;i3--;){let item1 = data34[i3];if(typeof item1 !== "string"){continue;}if(typeof indices1[item1] == "number"){j1 = indices1[item1];const err32 = {instancePath:instancePath+"/dependencies/" + key4.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/definitions/stringArray/uniqueItems",keyword:"uniqueItems",params:{i: i3, j: j1},message:"must NOT have duplicate items (items ## "+j1+" and "+i3+" are identical)",schema:true,parentSchema:schema7,data:data34};if(vErrors === null){vErrors = [err32];}else {vErrors.push(err32);}errors++;break;}indices1[item1] = i3;}}}else {const err33 = {instancePath:instancePath+"/dependencies/" + key4.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/definitions/stringArray/type",keyword:"type",params:{type: "array"},message:"must be array",schema:schema7.type,parentSchema:schema7,data:data34};if(vErrors === null){vErrors = [err33];}else {vErrors.push(err33);}errors++;}var _valid1 = _errs74 === errors;valid14 = valid14 || _valid1;}if(!valid14){const err34 = {instancePath:instancePath+"/dependencies/" + key4.replace(/~/g, "~0").replace(/\//g, "~1"),schemaPath:"#/properties/dependencies/additionalProperties/anyOf",keyword:"anyOf",params:{},message:"must match a schema in anyOf",schema:schema0.properties.dependencies.additionalProperties.anyOf,parentSchema:schema0.properties.dependencies.additionalProperties,data:data34};if(vErrors === null){vErrors = [err34];}else {vErrors.push(err34);}errors++;}else {errors = _errs72;if(vErrors !== null){if(_errs72){vErrors.length = _errs72;}else {vErrors = null;}}}}}else {const err35 = {instancePath:instancePath+"/dependencies",schemaPath:"#/properties/dependencies/type",keyword:"type",params:{type: "object"},message:"must be object",schema:schema0.properties.dependencies.type,parentSchema:schema0.properties.dependencies,data:data33};if(vErrors === null){vErrors = [err35];}else {vErrors.push(err35);}errors++;}}if(data.propertyNames !== undefined){if(!(validate0(data.propertyNames, {instancePath:instancePath+"/propertyNames",parentData:data,parentDataProperty:"propertyNames",rootData}))){vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);errors = vErrors.length;}}if(data.enum !== undefined){let data37 = data.enum;if(Array.isArray(data37)){if(data37.length < 1){const err36 = {instancePath:instancePath+"/enum",schemaPath:"#/properties/enum/minItems",keyword:"minItems",params:{limit: 1},message:"must NOT have fewer than 1 items",schema:1,parentSchema:schema0.properties.enum,data:data37};if(vErrors === null){vErrors = [err36];}else {vErrors.push(err36);}errors++;}let i4 = data37.length;let j2;if(i4 > 1){outer0:for(;i4--;){for(j2 = i4; j2--;){if(func0(data37[i4], data37[j2])){const err37 = {instancePath:instancePath+"/enum",schemaPath:"#/properties/enum/uniqueItems",keyword:"uniqueItems",params:{i: i4, j: j2},message:"must NOT have duplicate items (items ## "+j2+" and "+i4+" are identical)",schema:true,parentSchema:schema0.properties.enum,data:data37};if(vErrors === null){vErrors = [err37];}else {vErrors.push(err37);}errors++;break outer0;}}}}}else {const err38 = {instancePath:instancePath+"/enum",schemaPath:"#/properties/enum/type",keyword:"type",params:{type: "array"},message:"must be array",schema:schema0.properties.enum.type,parentSchema:schema0.properties.enum,data:data37};if(vErrors === null){vErrors = [err38];}else {vErrors.push(err38);}errors++;}}if(data.type !== undefined){let data38 = data.type;const _errs83 = errors;let valid20 = false;const _errs84 = errors;if(!(((((((data38 === "array") || (data38 === "boolean")) || (data38 === "integer")) || (data38 === "null")) || (data38 === "number")) || (data38 === "object")) || (data38 === "string"))){const err39 = {instancePath:instancePath+"/type",schemaPath:"#/definitions/simpleTypes/enum",keyword:"enum",params:{allowedValues: schema9.enum},message:"must be equal to one of the allowed values",schema:schema9.enum,parentSchema:schema9,data:data38};if(vErrors === null){vErrors = [err39];}else {vErrors.push(err39);}errors++;}var _valid2 = _errs84 === errors;valid20 = valid20 || _valid2;if(!valid20){const _errs86 = errors;if(Array.isArray(data38)){if(data38.length < 1){const err40 = {instancePath:instancePath+"/type",schemaPath:"#/properties/type/anyOf/1/minItems",keyword:"minItems",params:{limit: 1},message:"must NOT have fewer than 1 items",schema:1,parentSchema:schema0.properties.type.anyOf[1],data:data38};if(vErrors === null){vErrors = [err40];}else {vErrors.push(err40);}errors++;}const len2 = data38.length;for(let i5=0; i5<len2; i5++){let data39 = data38[i5];if(!(((((((data39 === "array") || (data39 === "boolean")) || (data39 === "integer")) || (data39 === "null")) || (data39 === "number")) || (data39 === "object")) || (data39 === "string"))){const err41 = {instancePath:instancePath+"/type/" + i5,schemaPath:"#/definitions/simpleTypes/enum",keyword:"enum",params:{allowedValues: schema9.enum},message:"must be equal to one of the allowed values",schema:schema9.enum,parentSchema:schema9,data:data39};if(vErrors === null){vErrors = [err41];}else {vErrors.push(err41);}errors++;}}let i6 = data38.length;let j3;if(i6 > 1){outer1:for(;i6--;){for(j3 = i6; j3--;){if(func0(data38[i6], data38[j3])){const err42 = {instancePath:instancePath+"/type",schemaPath:"#/properties/type/anyOf/1/uniqueItems",keyword:"uniqueItems",params:{i: i6, j: j3},message:"must NOT have duplicate items (items ## "+j3+" and "+i6+" are identical)",schema:true,parentSchema:schema0.properties.type.anyOf[1],data:data38};if(vErrors === null){vErrors = [err42];}else {vErrors.push(err42);}errors++;break outer1;}}}}}else {const err43 = {instancePath:instancePath+"/type",schemaPath:"#/properties/type/anyOf/1/type",keyword:"type",params:{type: "array"},message:"must be array",schema:schema0.properties.type.anyOf[1].type,parentSchema:schema0.properties.type.anyOf[1],data:data38};if(vErrors === null){vErrors = [err43];}else {vErrors.push(err43);}errors++;}var _valid2 = _errs86 === errors;valid20 = valid20 || _valid2;}if(!valid20){const err44 = {instancePath:instancePath+"/type",schemaPath:"#/properties/type/anyOf",keyword:"anyOf",params:{},message:"must match a schema in anyOf",schema:schema0.properties.type.anyOf,parentSchema:schema0.properties.type,data:data38};if(vErrors === null){vErrors = [err44];}else {vErrors.push(err44);}errors++;}else {errors = _errs83;if(vErrors !== null){if(_errs83){vErrors.length = _errs83;}else {vErrors = null;}}}}if(data.format !== undefined){let data40 = data.format;if(typeof data40 !== "string"){const err45 = {instancePath:instancePath+"/format",schemaPath:"#/properties/format/type",keyword:"type",params:{type: "string"},message:"must be string",schema:schema0.properties.format.type,parentSchema:schema0.properties.format,data:data40};if(vErrors === null){vErrors = [err45];}else {vErrors.push(err45);}errors++;}}if(data.contentMediaType !== undefined){let data41 = data.contentMediaType;if(typeof data41 !== "string"){const err46 = {instancePath:instancePath+"/contentMediaType",schemaPath:"#/properties/contentMediaType/type",keyword:"type",params:{type: "string"},message:"must be string",schema:schema0.properties.contentMediaType.type,parentSchema:schema0.properties.contentMediaType,data:data41};if(vErrors === null){vErrors = [err46];}else {vErrors.push(err46);}errors++;}}if(data.contentEncoding !== undefined){let data42 = data.contentEncoding;if(typeof data42 !== "string"){const err47 = {instancePath:instancePath+"/contentEncoding",schemaPath:"#/properties/contentEncoding/type",keyword:"type",params:{type: "string"},message:"must be string",schema:schema0.properties.contentEncoding.type,parentSchema:schema0.properties.contentEncoding,data:data42};if(vErrors === null){vErrors = [err47];}else {vErrors.push(err47);}errors++;}}if(data.if !== undefined){if(!(validate0(data.if, {instancePath:instancePath+"/if",parentData:data,parentDataProperty:"if",rootData}))){vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);errors = vErrors.length;}}if(data.then !== undefined){if(!(validate0(data.then, {instancePath:instancePath+"/then",parentData:data,parentDataProperty:"then",rootData}))){vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);errors = vErrors.length;}}if(data.else !== undefined){if(!(validate0(data.else, {instancePath:instancePath+"/else",parentData:data,parentDataProperty:"else",rootData}))){vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);errors = vErrors.length;}}if(data.allOf !== undefined){if(!(validate3(data.allOf, {instancePath:instancePath+"/allOf",parentData:data,parentDataProperty:"allOf",rootData}))){vErrors = vErrors === null ? validate3.errors : vErrors.concat(validate3.errors);errors = vErrors.length;}}if(data.anyOf !== undefined){if(!(validate3(data.anyOf, {instancePath:instancePath+"/anyOf",parentData:data,parentDataProperty:"anyOf",rootData}))){vErrors = vErrors === null ? validate3.errors : vErrors.concat(validate3.errors);errors = vErrors.length;}}if(data.oneOf !== undefined){if(!(validate3(data.oneOf, {instancePath:instancePath+"/oneOf",parentData:data,parentDataProperty:"oneOf",rootData}))){vErrors = vErrors === null ? validate3.errors : vErrors.concat(validate3.errors);errors = vErrors.length;}}if(data.not !== undefined){if(!(validate0(data.not, {instancePath:instancePath+"/not",parentData:data,parentDataProperty:"not",rootData}))){vErrors = vErrors === null ? validate0.errors : vErrors.concat(validate0.errors);errors = vErrors.length;}}}validate0.errors = vErrors;return errors === 0;}
]]>
https://jsonforms.discourse.group/t/issues-with-oneof-properties/2793#post_1 Tue, 18 Nov 2025 03:58:41 +0000 jsonforms.discourse.group-post-7028
Should JSON Forms core distinguish between readonly and disabled controls? At the moment, JSON Forms does not differentiate between readonly and disabled controls.
Renderers only receive information about whether a control is enabled or not, which means readOnly: true fields from the JSON Schema are effectively treated as disabled.

This causes a problem for renderer integrations like Vuetify (and likely others). In Vuetify, a disabled field appears gray and inactive, while a readonly field stays visually active but cannot be changed — a much better representation for non-editable but still relevant data.

The distinction between readonly and disabled is important not only for styling but also for semantics and accessibility:

  • readonly → visible, interactive in appearance, but not editable

  • disabled → unavailable, excluded from form interaction

Currently, renderers cannot reflect this difference because the core simply exposes an “enabled” flag.

It would be ideal if the core framework exposed both:

  • whether the control is enabled/disabled, and

  • whether the control is readonly (based on JSON Schema’s readOnly keyword and others).

That way, all renderers (Vuetify, Material, etc.) could properly represent readonly fields according to their design systems — without each renderer having to reinvent its own detection logic.

This feels like something that should be supported at the core level, since the concept of readOnly comes directly from JSON Schema and others, and should be part of the base control state model.

For backward compatibility we can still make the enabled to be false when the readonly is true but that should be more like an option that can be changed in order to support the new concept.

]]>
https://jsonforms.discourse.group/t/should-json-forms-core-distinguish-between-readonly-and-disabled-controls/2791#post_1 Wed, 12 Nov 2025 14:49:36 +0000 jsonforms.discourse.group-post-7026
Custom UISchema data on Custom Control Render (Angular) Hi @gmarinelli ,

We typically use an options object in a UISchemaElement to hand in custom properties. For instance, the abstract JsonFormsAbstractControl from the angular package uses this to determine whether the description should always be shown. See here: jsonforms/packages/angular/src/library/abstract-control.ts at b20bc25d8d546077c519f17288b83ea6f2091c6d · eclipsesource/jsonforms · GitHub

For instance, define your Group like this:

{
  type: "Group",
  scope: "#/properties/args",
  options: {
    someCustomParam: "some value"
  }
}

As your renderer transitively extends JsonFormsBaseRenderer, you can access the UI schema via this.uischema and the options via this.uischema.options. See here for the uischema definition in the base renderer: jsonforms/packages/angular/src/library/base.renderer.ts at b20bc25d8d546077c519f17288b83ea6f2091c6d · eclipsesource/jsonforms · GitHub

Hope that helps and best regards,
Lucas

]]>
https://jsonforms.discourse.group/t/custom-uischema-data-on-custom-control-render-angular/2788#post_2 Tue, 28 Oct 2025 14:57:18 +0000 jsonforms.discourse.group-post-7024
Custom UISchema data on Custom Control Render (Angular) I have a custom Renderer Set that uses Angular as the binding mechanism, but renders the components with Bootstrap 5 style. This is the custom renderer I have for GroupLayout:

@Component({
  selector: 'GroupLayoutRenderer',
  template: `
    <div class="card mb-1" [style.display]="hidden ? 'none' : ''">
      <div class="card-body px-2 pb-1 pt-{{ label ? 1 : 2 }}">
        <label class="card-title ps-1 text-muted small" *ngIf="label">{{ label }}</label>
        <div *ngFor="let props of uischema | layoutChildrenRenderProps: schema : path; trackBy: trackElement">
          <jsonforms-outlet [renderProps]="props"></jsonforms-outlet>
        </div>
      </div>
    </div>
  `,
  styles: [``],
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class GroupLayoutRenderer extends LayoutRenderer<GroupLayout> {
  constructor(jsonFormsService: JsonFormsAngularService, changeDetectionRef: ChangeDetectorRef) {
    super(jsonFormsService, changeDetectionRef);
  }
}
export const GroupLayoutTester: RankedTester = rankWith(1, uiTypeIs('Group'));

So, I can use a UISchema, like, for example:

{ type: "Group", scope: "#/properties/args", elements: [ ... ]}

What I need is to set a custom value into the UISchema and recover it on the renderer, so I can make this component change based on that custom parameter. For example:

{ type: "Group", someCustomParam: "some value", ... }

I already know how to generate the custom UISchema, the question is: How to get the custom parameter in the Angular custom renderer?

Thanks,
Cheers.

]]>
https://jsonforms.discourse.group/t/custom-uischema-data-on-custom-control-render-angular/2788#post_1 Wed, 22 Oct 2025 19:16:28 +0000 jsonforms.discourse.group-post-7022
Async dynamic enum for autocomplete text field Hi @perki ,

You have a look at the docs regarding re-using existing controls: Custom Renderers - JSON Forms

In any case you have to do the async fetching within the custom part of your code. You can look into reusing the MaterialEnumControl . To use it within your custom renderer’s code, use the unwrapped variant:

import { Unwrapped } from ‘@jsonforms/material-renderers’;
const { MaterialEnumControl } = Unwrapped;
]]>
https://jsonforms.discourse.group/t/async-dynamic-enum-for-autocomplete-text-field/2787#post_2 Tue, 21 Oct 2025 09:30:50 +0000 jsonforms.discourse.group-post-7021
Async dynamic enum for autocomplete text field While looking for a way to populate an enum or oneOf list for a text by fetching options.

I got a working solution with a custom renderer but using @mui/material

I would be pleased to have some hints about how I could use @jsonform/* Components instead;

There is a working demo on github: GitHub - perki/jsonforms-autocomplete-async-test: JsonForms AutoComplete Async Test

App.tsx see full content here

The Renderer takes an async callback options autoCompleteAsyncCallBack to fetch the data:

const uischema = {
   type: 'Control',
   scope: '#/properties/api_field',
   options: {
     autoCompleteAsyncCallBack,
     autoCompleteHelperText // optional, render a text when a choice is made
   }
};

AutoCompleteAsync.tsx

// AutoCompleteAsyncControl.js
import { useState, useEffect } from 'react';
import { withJsonFormsControlProps } from '@jsonforms/react';
import { Autocomplete , FormControl, TextField } from '@mui/material';

// no direct API import here; options are provided via uischema callback

interface AutoCompleteAsyncProps {
  data: any;
  handleChange(path: string, value: any): void;
  path: string;
  schema: JsonSchema;
  uischema: UISchemaElement;
}


export type AutoCompleteOption = {
  data: any,
  const: string,
  title: string
}

/**
 * @return a textual description of the selected item if any
 */
export type AutoCompleteAsyncCallBack = (query: string) => Promise<AutoCompleteOption[]>;

/**
 * @return a textual description of the selected item if any
 */
export type AutoCompleteHelperText = (option: AutoCompleteOption) => string;

const AutoCompleteAsyncControl = ({ data, handleChange, path, schema, uischema }: AutoCompleteAsyncProps) => {
  // -- load from usischema config
  const autoCompleteAsyncCallBack: AutoCompleteAsyncCallBack = uischema?.options?.autoCompleteAsyncCallBack;
  if (autoCompleteAsyncCallBack == null) throw new Error('Missing uischema.options.autoCompleteAsyncCallBack');
  const autoCompleteHelperText: AutoCompleteHelperText = uischema?.options?.autoCompleteHelperText || (() => schema.description);
  // --
  const [options, setOptions] = useState<AutoCompleteOption[]>([]);
  const [loading, setLoading] = useState(true);
  const [inputValue, setInputValue] = useState( data?.title || '');

  // API call on input change
  useEffect(() => {
    const fetchOptions = async () => {
      setLoading(true);
      try {
        const newOptions = await autoCompleteAsyncCallBack(inputValue);
        if (Array.isArray(newOptions)) {
          setOptions(newOptions);
        } else {
          setOptions([]);
        }
      } catch (error) {
        setOptions([]);
        console.error('Failed to fetch options:', error);
      } finally {
        setLoading(false);
      }
    };
    fetchOptions();
  }, [inputValue]);

  const myOnChange = function (event: any, newValue: AutoCompleteOption | null) {
    handleChange(path, newValue);
  };

  const newInputValue = function (event: any, newInputValue: string) {
    if (event == null) return; // avoid change on init
    setInputValue(newInputValue);
  };

  return (
    <FormControl fullWidth>
      <Autocomplete
        options={options}
        loading={loading}
        forcePopupIcon={false}
        onChange={myOnChange}
        inputValue={inputValue}
        onInputChange={newInputValue}
        getOptionLabel={(option) => option?.title ?? ''}
        isOptionEqualToValue={(option, value) => option?.const === value?.const}
        renderOption={(liProps, option) => (
          <li {...liProps} key={option.const}>{option.title}</li>
        )}
        renderInput={(params) => (
          <TextField
            {...params}
            label={schema.title || path}
            helperText={autoCompleteHelperText(data)}
          />
        )}
      />
    </FormControl>
  );
};

// --- Tester
import { rankWith, hasOption, isStringControl, and, UISchemaElement, JsonSchema } from '@jsonforms/core';

// This tester will trigger the custom renderer when a UI schema control has
// a specific custom property, like "render: 'autocomplete-api'".
export const AutocompleteAsyncTester = rankWith(
  3, // A higher rank gives this renderer precedence
  and(
    isStringControl,
    hasOption('autoCompleteAsyncCallBack')
  )
);


const AutoCompleteAsyncRenderer = withJsonFormsControlProps(AutoCompleteAsyncControl);

export default AutoCompleteAsyncRenderer;


]]>
https://jsonforms.discourse.group/t/async-dynamic-enum-for-autocomplete-text-field/2787#post_1 Wed, 15 Oct 2025 15:26:19 +0000 jsonforms.discourse.group-post-7020
How to customize the element style, eg height / margin how to adjust the row height / maybe row spacing . through css ?

.MuiGrid-container{

row-gap: 20px !important;

height: 100px !important;

}

]]>
https://jsonforms.discourse.group/t/how-to-customize-the-element-style-eg-height-margin/2741#post_5 Tue, 14 Oct 2025 15:25:53 +0000 jsonforms.discourse.group-post-7018
How to customize the element style, eg height / margin how to adjust the row height / maybe row spacing . through css ?

]]>
https://jsonforms.discourse.group/t/how-to-customize-the-element-style-eg-height-margin/2741#post_4 Tue, 14 Oct 2025 10:55:48 +0000 jsonforms.discourse.group-post-7017
Vuetify stepper labels Hello @kfleming ,

You are right, currently the text is rendered in the stepper item’s default slot (see code below) and, thus, is not hidden when the mobile flag is set to true. I think we could change the code to render the label in the title slot instead allowing it to be hidden by the mobile flag. If you’d like, you can open a PR for that.

Unfortunately, you cannot currently set the title or subtitle directly via the UI Schema: The UI Schema only allows settings component props but not slots.

Kind regards,

Lucas

]]>
https://jsonforms.discourse.group/t/vuetify-stepper-labels/2779#post_2 Fri, 10 Oct 2025 08:45:14 +0000 jsonforms.discourse.group-post-7015
Problem with MaterialUI DatePicker French traduction Hi @EtienneS76 ,

this might actually be a (refresh) problem in JSON Forms. Or a problem of the locale being overridden somewhere in JSON Forms.

I can reproduce something similar to this:

I define the dayjs.locale(‘fr’) and it’s work because when i use a DatePicker in the same component i have correct french labels

I tested in the JSON Forms React seed. After configuring dayjs.locale(‘fr’) either once in main.tsx or in the JsonFormsDemo component, the date renderer uses french locale on first open. However, after closing it and opening the picker again, the texts return to English.

The locale for JSON Forms general translation provided via the i18n prop also does not affect this.

Could you open an issue for this at GitHub · Where software is built ?

Thanks and kind regards,

Lucas

]]>
https://jsonforms.discourse.group/t/problem-with-materialui-datepicker-french-traduction/2783#post_2 Mon, 06 Oct 2025 08:28:53 +0000 jsonforms.discourse.group-post-7014
Angular JSONForms oneOf with custom radio renderer: selected branch does not show any fields Hi @vsam ,

it seems that you have only one control pointing to #/properties/affectedPerson that is rendered by your custom renderer that then uses the ui schema given in the detail somehow?

While we don’t have a oneOf Angular renderer so far that you can look at, you could look at the react material oneof renderer as hints on how to render the child properties: jsonforms/packages/material-renderers/src/complex/MaterialOneOfRenderer.tsx at 016f1dff9653ac2e977564cbd6d850593309c551 · eclipsesource/jsonforms · GitHub

Best regards,

Lucas

]]>
https://jsonforms.discourse.group/t/angular-jsonforms-oneof-with-custom-radio-renderer-selected-branch-does-not-show-any-fields/2781#post_2 Mon, 06 Oct 2025 07:31:27 +0000 jsonforms.discourse.group-post-7013
Is there a way to map ajv error object to field control New AJV i guess does not have a data path it has instancePath, not sure how to map it, also message is 1 - required, what we want is State Name - requried

{
    "instancePath": "/states/1",
    "schemaPath": "#/properties/states/items/required",
    "keyword": "required",
    "params": {
        "missingProperty": "state_name"
    },
    "message": " Required",
    "schema": [
        "state_name"
    ],
    "data": {
        "state_properties": {},
        "cities": []
    },
    "child_error_message": "1 -  Required"
}
]]>
https://jsonforms.discourse.group/t/is-there-a-way-to-map-ajv-error-object-to-field-control/2782#post_3 Fri, 03 Oct 2025 05:55:25 +0000 jsonforms.discourse.group-post-7011
Problem with MaterialUI DatePicker French traduction Hello everyone, I’m experiencing an issue with Material-UI DatePicker not displaying French text despite having properly configured the locale settings.

I define the dayjs.locale(‘fr’) and it’s work because when i use a DatePicker in the same component i have correct french labels

Despite all these configurations pointing to French locale, the DatePicker still displays: Month names in English (January, February, etc.) Button labels in English (“Cancel”, “OK” instead of “Annuler”, “OK”) Day abbreviations in English

Is there an additional step I’m missing for Material-UI DatePicker localization within JSONForms? Do I need to import specific Material-UI locale files or configure something else?

Any help would be greatly appreciated!

Environment:

  • @jsonforms/react

  • @jsonforms/material-renderers

  • @mui/x-date-pickers

  • dayjs

]]>
https://jsonforms.discourse.group/t/problem-with-materialui-datepicker-french-traduction/2783#post_1 Thu, 02 Oct 2025 13:22:07 +0000 jsonforms.discourse.group-post-7010
Same property names - can't load some options/rules declared in the uiSchema @sdirix Just checking in to see if anyone has had a chance to look into the issue I raised. Were you able to reproduce it locally?

I’d really appreciate any feedback you can share.

Thanks again!

]]>
https://jsonforms.discourse.group/t/same-property-names-cant-load-some-options-rules-declared-in-the-uischema/2777#post_4 Thu, 02 Oct 2025 08:06:23 +0000 jsonforms.discourse.group-post-7009
Is there a way to map ajv error object to field control Yes, the error object contains the schema and data paths required to map it. That’s how we do it for all errors. If you like to show errors in different places than foreseen by JSON Forms, then you need to filter/collect them manually from the form-wide error storage

]]>
https://jsonforms.discourse.group/t/is-there-a-way-to-map-ajv-error-object-to-field-control/2782#post_2 Wed, 01 Oct 2025 10:18:58 +0000 jsonforms.discourse.group-post-7008
Is there a way to map ajv error object to field control Right now I am getting error from AJV for required min items, is there a way to map AJV error to field control

]]>
https://jsonforms.discourse.group/t/is-there-a-way-to-map-ajv-error-object-to-field-control/2782#post_1 Wed, 01 Oct 2025 09:50:11 +0000 jsonforms.discourse.group-post-7007
Angular JSONForms oneOf with custom radio renderer: selected branch does not show any fields I’m trying to use JSONForms with a custom radio renderer to handle a oneOf.
The idea is simple: select Natural person OR Legal person via radio buttons → only that branch’s fields should show up.

But when I select an option, no fields are rendered under the radio, even though the radio changes.

“type”: “object”,
“properties”: {
“affectedPerson”: {
“oneOf”: [
{
“title”: “Natural”,
“type”: “object”,
“properties”: {
“affectedPersonNatural”: {
“type”: “object”,
“properties”: {
“firstName”: { “type”: “string” },
“lastName”: { “type”: “string” }
}
}
},
“required”: [“affectedPersonNatural”]
},
{
“title”: “Legal”,
“type”: “object”,
“properties”: {
“affectedPersonLegal”: {
“type”: “object”,
“properties”: {
“companyName”: { “type”: “string” },
“legalForm”: { “type”: “string” }
}
}
},
“required”: [“affectedPersonLegal”]
}
]
}
}
}

UI Schema

{
“type”: “VerticalLayout”,
“elements”: [
{
“type”: “Control”,
“scope”: “#/properties/affectedPerson”,
“label”: “Affected Person”,
“options”: {
“detail”: {
“type”: “VerticalLayout”,
“elements”: [
{
“type”: “Group”,
“label”: “Natural person”,
“elements”: [
{
“type”: “Control”,
“scope”: “#/properties/affectedPersonNatural/properties/firstName”,
“label”: “First name”
},
{
“type”: “Control”,
“scope”: “#/properties/affectedPersonNatural/properties/lastName”,
“label”: “Last name”``}
]
},
{
“type”: “Group”,
“label”: “Legal person”,
“elements”: [`
{
“type”: “Control”,
“scope”: “#/properties/affectedPersonLegal/properties/companyName”,
“label”: “Company name”
},
{
“type”: “Control”,
“scope”: “#/properties/affectedPersonLegal/properties/legalForm”,
“label”: “Legal form”`
}
]
}
]
}
}
}
]
}
]]>
https://jsonforms.discourse.group/t/angular-jsonforms-oneof-with-custom-radio-renderer-selected-branch-does-not-show-any-fields/2781#post_1 Tue, 30 Sep 2025 16:34:42 +0000 jsonforms.discourse.group-post-7006
Vuetify stepper labels Hello,

I’ve just started out with JSONForms and I’m trying to create a stepper for a mobile friendly site using the Vuetify render set. The issue that I’m having is with label rendering. I want the stepper labels to disappear when I add the mobile flag to my UI schema.

"uischema":
    {
        "type": "Categorization",
        "elements":
        [
            {
                "type": "Category",
                "label": "Age",
                "elements":
                [
                    {
                        "type": "Control",
                        "scope": "#/properties/age"
                    }
                ]
            },
...
"options":
        {
            "variant": "stepper",
            "showNavButtons": true,
            "vertical": false,
            "vuetify": {
            	"v-stepper": {
            		"mobile": true
            	}
            }
        }
}

Unfortunately when I use the ‘label’ key the text gets rendered as a text node inside the v-stepper-item__content element and doesn’t get hidden by the css rules when the v-stepper--mobile class is added to the stepper container div. Ideally I’d like to populate the VStepperItem component slots for title and subtitle but I’m not clear on how to do this from the uischema?
Any help appreciated!

]]>
https://jsonforms.discourse.group/t/vuetify-stepper-labels/2779#post_1 Thu, 25 Sep 2025 13:19:42 +0000 jsonforms.discourse.group-post-7004
Making a custom UISchema type Scoped in TypeScript We are going with solution 1 because we are incontrol of the schema. In the case of strings that represent money or dates we will use format in the data schema but for controls with data contracts we prefer to be explicit. For instance our autocompletes are backed by standard search URLs for selections that are passed in an options property.

In any case this works, It is mostly a concern for tests and not tripping our build linters. In the majority of cases the schemas will come in as JSON from the server. It would be nice if there was a documented way to just extend UISchemaElement using declare module, but I haven’t been able to figure out the right way to describe it so that the JSONForms interface accepts the new type. Note I used this for brevity:

export interface AutocompleteControlElement extends Omit<ControlElement, 'type'> {
  type: 'AutocompleteControl';
}

This way you only have one import and are a bit shielded from future versions extending Control with other interfaces.

]]>
https://jsonforms.discourse.group/t/making-a-custom-uischema-type-scoped-in-typescript/2778#post_3 Tue, 23 Sep 2025 13:58:14 +0000 jsonforms.discourse.group-post-7003
Making a custom UISchema type Scoped in TypeScript Hi @J5live ,

The issue stems from the definition of the UISchemaElement type:

/**
 * A union of all available UI schema elements.
 * This includes all layout elements, control elements, label elements,
 * group elements, category elements and categorization elements.
 */
export type UISchemaElement = BaseUISchemaElement | ControlElement | Layout | LabelElement | GroupLayout | Category | Categorization | VerticalLayout | HorizontalLayout;

This marks your scope as an unknown property.

Solution 1: Cast to appropriate type

You should be able to define an interface like this for an autocomplete control.

import { BaseUISchemaElement, Scoped } from '@jsonforms/core';

interface AutocompleteControl extends BaseUISchemaElement, Scoped {
  type: 'Autocomplete';
}

You then need to explicitly cast your element to this type. Then it is recognized as a UISchemaElement because BaseUISchemaElement is allowed.

You can also directly cast you element to BaseUISchemaElement.

Solution 2: Use a UISchema option to identify the control in your tester

Each Control element can have arbitrary options like so:

{
  type: "Control",
  scope: "#/properties/users",
  options: {
    customAutocomplete: true
  }
}

Then, in your tester you can check this:

export const autocompleteJsonFormControlTester = rankWith(
  3,
  optionIs("customAutocomplete", true)
);

I would recommend solution 2.

]]>
https://jsonforms.discourse.group/t/making-a-custom-uischema-type-scoped-in-typescript/2778#post_2 Tue, 23 Sep 2025 07:48:08 +0000 jsonforms.discourse.group-post-7002