# Wrapping any JSONForms formfield

**URL:** <https://jsonforms.discourse.group/t/wrapping-any-jsonforms-formfield/2030>\
**Category:** General\
**Created:** [March 18, 2024, 9:38am UTC](https://jsonforms.discourse.group/t/wrapping-any-jsonforms-formfield/2030 "2024-03-18T09:38:41Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Sewdn](https://yyz2.discourse-cdn.com/free1/user_avatar/jsonforms.discourse.group/sewdn/32/488_2.png) [@Sewdn](https://jsonforms.discourse.group/u/Sewdn)\
**Post date:** [March 18, 2024, 9:38am UTC](https://jsonforms.discourse.group/t/wrapping-any-jsonforms-formfield/2030/1 "2024-03-18T09:38:41Z")

</div>

Hi,

when trying to add a generic wrapper around JsonForm form fields, I encounter problems for propagating the right props to the underlying components.

The idea is to add a custom renderer that, depending on available properties in the schema, will add a wrapping div around the form field with some custom classes.

The problem is that when using the `withJsonFormsControlProps` HOC, the schema prop of the underlying component, rendered by using the `JsonFormsDispatch` component, needs to replaced by the root schema in order to keep all the custom props for other custom renderers.

But when doing this, the default prop is lost in the process, because no defaults are being rendered any more.

Could you please tell me how to use `withJsonFormControlProps` and `JsonFormsDispatch` properly to achieve what I’m looking for? Thanks! Here is my current implementation of the Wrapper renderer:

```auto
const WrapperRenderer = (props: ControlProps) => {
  const hasProp = (p: string) => props.schema.hasOwnProperty(p);
  const isEssential = hasProp('isEssential');
  const inCalculation = hasProp('inCalculation');

  const classes = useStyles();
  return (
    <div
      className={clsx(classes.wrapped, {
        [classes.essential]: isEssential,
        [classes.calculation]: inCalculation,
        [classes.both]: isEssential && inCalculation,
      })}
    >
      <JsonFormsDispatch {...props} schema={props.rootSchema} renderers={renderers(['wrapper'])} />
    </div>
  );
};

export default withJsonFormsControlProps(WrapperRenderer);

export const isWrapperControl = and(
  uiTypeIs('Control'),
  schemaMatches(
    (schema) =>
      !isEmpty(schema) &&
      (schema.hasOwnProperty('isEssential') || schema.hasOwnProperty('inCalculation')),
  ),
);

export const tester = rankWith(10000, isWrapperControl);

```

Some example schema:

```auto
export const example: JsonFormSchemas = {
  schema: {
    type: 'object',
    properties: {
      firstName: {
        type: 'string',
        default: 'John', // displayed correctly
        readOnly: true, // correctly being disabled
      },
      lastName: {
        type: 'string',
        isEssential: true,
        default: 'Doe', // NOT being displayed correctly (because wrapped by Wrapper component)
        readOnly: true, // NOT being disabled
      },
      density: {
        type: 'integer',
        unit: '<sup>kg</sup>&frasl;<sub>m<sup>3</sup></sub>',
        isEssential: true,
        inCalculation: true,
        default: 15, // NOT being used
        minimum: 10,
        maximum: 20,
      },
      density2: {
        type: 'integer',
        unit: '<sup>kg</sup>&frasl;<sub>m<sup>3</sup></sub>',
        inCalculation: true,
        default: 15, // NOT being used
        minimum: 10,
        maximum: 20,
      },
    },
    required: ['lastName', 'density'],
  },
  data: {},
};

```

Now, when I remove the `withJsonFormsControlProps` HOC, the `readOnly` and `disabled` prop are being used correctly, but the wrapper classes are not set, because the schema of the Wrapper renderer is replaced by the root schema.

---

<div class="post-metadata">

**Author:** ![Sewdn](https://yyz2.discourse-cdn.com/free1/user_avatar/jsonforms.discourse.group/sewdn/32/488_2.png) [@Sewdn](https://jsonforms.discourse.group/u/Sewdn)\
**Post date:** [March 18, 2024, 11:24am UTC](https://jsonforms.discourse.group/t/wrapping-any-jsonforms-formfield/2030/2 "2024-03-18T11:24:26Z")

</div>

I have now resolved the prop schema of the current control myself in the renderer with following code. I also used the `withJsonFormsRendererProps` HOC instead of the `withJsonFormsControlProps`.

This way it works as expected.  
Is this the way to go?

```auto
const WrapperRenderer = (props: JsonFormsProps) => {
  const resolvedSchema = Resolve.schema(
    props.schema ?? props.rootSchema,
    // @ts-expect-error
    props.uischema?.scope ?? '',
    props.rootSchema,
  );

  const hasProp = (p: string) => resolvedSchema?.hasOwnProperty(p) ?? false;
  const isEssential = hasProp('isEssential');
  const inCalculation = hasProp('inCalculation');

  const classes = useStyles();
  return (
    <div
      className={clsx(classes.wrapped, {
        [classes.essential]: isEssential,
        [classes.calculation]: inCalculation,
        [classes.both]: isEssential && inCalculation,
      })}
    >
      <JsonFormsDispatch {...props} renderers={renderers(['wrapper'])} />
    </div>
  );
};

export default withJsonFormsRendererProps(WrapperRenderer);

```

---

<div class="post-metadata">

**Author:** ![sdirix](https://yyz2.discourse-cdn.com/free1/user_avatar/jsonforms.discourse.group/sdirix/32/1073_2.png) [@sdirix](https://jsonforms.discourse.group/u/sdirix)\
**Post date:** [March 18, 2024, 4:07pm UTC](https://jsonforms.discourse.group/t/wrapping-any-jsonforms-formfield/2030/3 "2024-03-18T16:07:39Z")

</div>

Hi @Sewdn,

Bindings like `withJsonFormsControlProps` work like this: They receive the props handed over to `JsonFormsDispatch` and consume the form-wide state. Based on these two data points they then determine the specific props handed over to the renderers.

# Example

The `JsonFormsDispatch` receives `schema`

```auto
{
  "title": "Person",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "default": "John Doe"
    },
  }
}

```

and `uischema`

```auto
{
  "type": "Control"
  "scope": "#/properties/name"
}

```

The `withJsonFormsControlProps` will be given these as props, and then at the end determine the following `schema` and `uischema` props for the control renderer

```auto
{
  "type": "string",
  "default": "John Doe"
}

```

```auto
{
  "type": "Control"
  "scope": "#/properties/name"
}

```

As you can see, the control renderer receives the already resolved sub schema of `schema` so it can directly access it and doesn’t need to do the resolving itself.

This is why using `withJsonFormsControlProps` in the “wrapper” does not work when it then calls `JsonFormsDispatch` again. The `uischema` and sub `schema` don’t fit together.

**What would work** is calling a specific unwrapped renderer here, so instead of calling `JsonFormsDispatch` you would call `Unwrapped.MaterialTextControl` instead, see [here for the wrapping documentation](https://jsonforms.io/docs/tutorial/custom-renderers#reusing-existing-controls).

* * *

> [@Sewdn](#):
>
> I have now resolved the prop schema of the current control myself in the renderer with following code. I also used the `withJsonFormsRendererProps` HOC instead of the `withJsonFormsControlProps`.

Yes, that works because `withJsonFormsRendererProps`, in contrast to `withJsonFormsControlProps`, [does almost nothing](https://github.com/eclipsesource/jsonforms/blob/24f4e5f6280263a4b8e1263aa2a302613b546272/packages/core/src/util/renderer.ts#L986-L1000). As the props given to `JsonFormsDispatch` are not modified, you can call `JsonFormsDispatch` again without breaking anything. Of course you then need to manually execute some of the functionality of `withJsonFormsControlProps` if you need it, e.g. resolving the `schema`.

---

<div class="post-metadata">

**Author:** ![Sewdn](https://yyz2.discourse-cdn.com/free1/user_avatar/jsonforms.discourse.group/sewdn/32/488_2.png) [@Sewdn](https://jsonforms.discourse.group/u/Sewdn)\
**Post date:** [March 18, 2024, 4:27pm UTC](https://jsonforms.discourse.group/t/wrapping-any-jsonforms-formfield/2030/4 "2024-03-18T16:27:43Z")

</div>

Hi @sdirix

thanks for your response.

> **What would work** is calling a specific unwrapped renderer here, so instead of calling `JsonFormsDispatch` you would call `Unwrapped.MaterialTextControl` instead

This is not desirable because I would need to map to all of the available Unwrapped controls. Also custom controls. So I would need to keep updating this Wrapper renderer when new Custom Renderers are added.

I stick to resolving the schema in the Wrapper renderer manually (based on the rootSchema and the scope prop of the uischema).

---

<div class="post-metadata">

**Author:** ![sdirix](https://yyz2.discourse-cdn.com/free1/user_avatar/jsonforms.discourse.group/sdirix/32/1073_2.png) [@sdirix](https://jsonforms.discourse.group/u/sdirix)\
**Post date:** [March 18, 2024, 4:49pm UTC](https://jsonforms.discourse.group/t/wrapping-any-jsonforms-formfield/2030/5 "2024-03-18T16:49:11Z")

</div>

Hi @Sewdn,

Feel free to use the `withJsonFormsRendererProps` approach. Just wanted to make clear what needs to be done if `withJsonFormsControlProps` is used.
