Skip to main content
Version: v5

Custom Templates

This is an advanced feature that lets you customize even more aspects of the form:

Custom FieldCustom TemplateCustom Widget
What it doesOverrides all behaviourOverrides just the layout (not behaviour)Overrides just the input box (not layout, labels, or help, or validation)
UsageGlobal or per-fieldGlobal or per-fieldGlobal or per-field
Global Example<Form fields={{ MyCustomField }} /><Form templates={{ ArrayFieldTemplate: MyArrayTemplate }} /><Form widgets={{ MyCustomWidget }} />
Per-Field Example"ui:field": MyCustomField"ui:ArrayFieldTemplate": MyArrayTemplate"ui:widget":MyCustomWidget
DocumentationCustom FieldsSee documentation belowCustom Widgets

In version 5, all existing templates were consolidated into a new TemplatesType interface that is provided as part of the Registry. They can also be overloaded globally on the Form via the templates prop as well as globally or per-field through the uiSchema. Further, many new templates were added or repurposed from existing widgets and fields in an effort to simplify the effort needed by theme authors to build new and/or maintain current themes. These new templates can also be overridden by individual users to customize the specific needs of their application. A special category of templates, ButtonTemplates, were also added to support the easy replacement of the Submit button on the form, the Add and Remove buttons associated with additionalProperties on objects and elements of arrays, as well as the Move up and Move down buttons used for reordering arrays. This category, unlike the others, can only be overridden globally via the templates prop on Form.

Below is the table that lists all the templates, their props interface, their uiSchema name and from where they originated in the previous version of RJSF:

Template*Props TypeUiSchema nameOrigin
ArrayFieldTemplateArrayFieldTemplatePropsui:ArrayFieldTemplateFormerly Form.ArrayFieldTemplate or Registry.ArrayFieldTemplate
ArrayFieldDescriptionTemplate*ArrayFieldDescriptionPropsui:ArrayFieldDescriptionTemplateFormerly part of @rjsf/core ArrayField, refactored as a template, used in all ArrayFieldTemplate implementations
ArrayFieldItemTemplate*ArrayFieldTemplateItemTypeui:ArrayFieldItemTemplateFormerly an internal class for ArrayFieldTemplates in all themes, refactored as a template in each theme, used in all ArrayFieldTemplate implementations
ArrayFieldTitleTemplate*ArrayFieldTitlePropsui:ArrayFieldTitleTemplateFormerly part of @rjsf/core ArrayField, refactored as a template, used in all ArrayFieldTemplate implementations.
BaseInputTemplate*WidgetPropsui:BaseInputTemplateFormerly a widget in @rjsf.core moved to templates and newly implemented in each theme to maximize code reuse.
DescriptionFieldTemplate*DescriptionFieldPropsui:DescriptionFieldTemplateFormerly a field in @rjsf.core moved to templates with the Template suffix. Previously implemented in each theme.
ErrorListTemplate*ErrorListPropsui:ErrorListTemplateFormerly Form.ErrorList moved to templates with the Templates suffix. Previously implemented in each theme.
FieldErrorTemplate*FieldErrorPropsui:FieldErrorTemplateFormerly internal ErrorList component accessible only to SchemaField
FieldHelpTemplate*FieldHelpPropsui:FieldHelpTemplateFormerly internal Help component accessible only to SchemaField
FieldTemplateFieldTemplatePropsui:FieldTemplateFormerly Form.FieldTemplate or Registry.FieldTemplate
ObjectFieldTemplateObjectFieldTemplatePropsui:ObjectFieldTemplateFormerly Form.ObjectFieldTemplate or Registry.ObjectFieldTemplate
TitleFieldTemplate*TitleFieldPropsui:TitleFieldTemplateFormerly a field in @rjsf.core moved to templates with the Template suffix. Previously implemented in each theme.
UnsupportedFieldTemplate*UnsupportedFieldPropsui:UnsupportedFieldTemplateFormerly a field in @rjsf.core moved to templates with the Template suffix.
WrapIfAdditionalTemplate*WrapIfAdditionalTemplatePropsui:WrapIfAdditionalTemplateFormerly an internal component in @rjsf.core. Previously implemented in most themes.
ButtonTemplates.AddButton*IconButtonPropsn/aFormerly an internal implementation in each theme
ButtonTemplates.MoveDownButton*IconButtonPropsn/aFormerly an internal implementation in each theme
ButtonTemplates.MoveUpButton*IconButtonPropsn/aFormerly an internal implementation in each theme
ButtonTemplates.RemoveButton*IconButtonPropsn/aFormerly an internal implementation in each theme
ButtonTemplates.SubmitButton*SubmitButtonPropsn/aFormerly a field in each theme move to templates.ButtonTemplates

* indicates a new template in version 5

ArrayFieldTemplate

You can use an ArrayFieldTemplate to customize how your arrays are rendered. This allows you to customize your array, and each element in the array. If you only want to customize how the array's title, description or how the array items are presented, you may want to consider providing your own ArrayFieldDescriptionTemplate, ArrayFieldItemTemplate and/or ArrayFieldTitleTemplate instead. You can also customize arrays by specifying a widget in the relevant ui:widget schema, more details over on Custom Widgets.

import { ArrayFieldTemplateProps, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'array',
items: {
type: 'string',
},
};

function ArrayFieldTemplate(props: ArrayFieldTemplateProps) {
return (
<div>
{props.items.map((element) => element.children)}
{props.canAdd && <button type='button' onClick={props.onAddClick}></button>}
</div>
);
}

render(
<Form schema={schema} validator={validator} templates={{ ArrayFieldTemplate }} />,
document.getElementById('app')
);

You also can provide your own field template to a uiSchema by specifying a ui:ArrayFieldTemplate property.

import { UiSchema } from '@rjsf/utils';

const uiSchema: UiSchema = {
'ui:ArrayFieldTemplate': ArrayFieldTemplate,
};

Please see the customArray.tsx sample from the playground for another example.

The following props are passed to each ArrayFieldTemplate:

  • canAdd: A boolean value stating whether new elements can be added to the array.
  • className: The className string.
  • disabled: A boolean value stating if the array is disabled.
  • idSchema: An object containing the id for this object & ids for its properties
  • items: An array of objects representing the items in the array. Each of the items represent a child with properties described below.
  • onAddClick: (event?) => void: A function that adds a new item to the array.
  • readonly: A boolean value stating if the array is read-only.
  • required: A boolean value stating if the array is required.
  • hideError: A boolean value stating if the field is hiding its errors.
  • schema: The schema object for this array.
  • uiSchema: The uiSchema object for this array field.
  • title: A string value containing the title for the array.
  • formContext: The formContext object that you passed to Form.
  • formData: The formData for this array.
  • errorSchema: The optional validation errors for the array field and the items within it, in the form of an ErrorSchema
  • rawErrors: An array of strings listing all generated error messages from encountered errors for this widget
  • registry: The registry object.

The following props are part of each element in items:

  • children: The html for the item's content.
  • className: The className string.
  • disabled: A boolean value stating if the array item is disabled.
  • hasCopy: A boolean value stating whether the array item can be copied.
  • hasMoveDown: A boolean value stating whether the array item can be moved down.
  • hasMoveUp: A boolean value stating whether the array item can be moved up.
  • hasRemove: A boolean value stating whether the array item can be removed.
  • hasToolbar: A boolean value stating whether the array item has a toolbar.
  • index: A number stating the index the array item occurs in items.
  • key: A stable, unique key for the array item.
  • onAddIndexClick: (index) => (event?) => void: Returns a function that adds a new item at index.
  • onDropIndexClick: (index) => (event?) => void: Returns a function that removes the item at index.
  • onReorderClick: (index, newIndex) => (event?) => void: Returns a function that swaps the items at index with newIndex.
  • readonly: A boolean value stating if the array item is read-only.
  • uiSchema: The uiSchema object for this array item.
  • registry: The registry object.

Note: Array and object field templates are always rendered inside the FieldTemplate. To fully customize an array field template, you may need to specify both ui:FieldTemplate and ui:ArrayFieldTemplate.

ArrayFieldDescriptionTemplate

The out-of-the-box version of this template will render the DescriptionFieldTemplate with a generated id, if there is a description otherwise nothing is rendered. If you want different behavior for the rendering of the description of an array field, you can customize this template. If you want a different behavior for the rendering of ALL descriptions in the Form, see DescriptionFieldTemplate

import { ArrayFieldDescriptionProps, RJSFSchema, descriptionId } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'array',
items: {
type: 'string',
},
};

function ArrayFieldDescriptionTemplate(props: ArrayFieldDescriptionProps) {
const { description, idSchema } = props;
const id = descriptionId(idSchema);
return (
<details id={id}>
<summary>Description</summary>
{description}
</details>
);
}

render(
<Form schema={schema} validator={validator} templates={{ ArrayFieldDescriptionTemplate }} />,
document.getElementById('app')
);

You also can provide your own template to a uiSchema by specifying a ui:ArrayFieldDescriptionTemplate property.

import { UiSchema } from '@rjsf/utils';

const uiSchema: UiSchema = {
'ui:ArrayFieldDescriptionTemplate': ArrayFieldDescriptionTemplate,
};

The following props are passed to each ArrayFieldDescriptionTemplate:

  • description: The description of the array field being rendered.
  • idSchema: The idSchema of the array field in the hierarchy.
  • schema: The schema object for this array field.
  • uiSchema: The uiSchema object for this array field.
  • registry: The registry object.

ArrayFieldItemTemplate

The ArrayFieldItemTemplate is used to render the representation of a single item in an array. All of the ArrayFieldTemplate implementations in all themes get this template from the registry in order to render array fields items. Each theme has an implementation of the ArrayFieldItemTemplate to render an array field item in a manner best suited to the theme. If you want to change how an array field item is rendered you can customize this template (for instance to remove the move up/down and remove buttons).

import { ArrayFieldTemplateItemType, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'array',
items: {
type: 'string',
},
};

function ArrayFieldItemTemplate(props: ArrayFieldTemplateItemType) {
const { children, className } = props;
return <div className={className}>{children}</div>;
}

render(
<Form schema={schema} validator={validator} templates={{ ArrayFieldItemTemplate }} />,
document.getElementById('app')
);

The following props are passed to each ArrayFieldItemTemplate:

  • children: The html for the item's content.
  • className: The className string.
  • disabled: A boolean value stating if the array item is disabled.
  • canAdd: A boolean value stating whether new items can be added to the array.
  • hasCopy: A boolean value stating whether the array item can be copied.
  • hasMoveDown: A boolean value stating whether the array item can be moved down.
  • hasMoveUp: A boolean value stating whether the array item can be moved up.
  • hasRemove: A boolean value stating whether the array item can be removed.
  • hasToolbar: A boolean value stating whether the array item has a toolbar.
  • index: A number stating the index the array item occurs in items.
  • totalItems: A number stating the total number items in the array.
  • key: A stable, unique key for the array item.
  • onAddIndexClick: (index) => (event?) => void: Returns a function that adds a new item at index.
  • onDropIndexClick: (index) => (event?) => void: Returns a function that removes the item at index.
  • onReorderClick: (index, newIndex) => (event?) => void: Returns a function that swaps the items at index with newIndex.
  • readonly: A boolean value stating if the array item is read-only.
  • schema: The schema object for this array item.
  • uiSchema: The uiSchema object for this array item.
  • registry: The registry object.

ArrayFieldTitleTemplate

The out-of-the-box version of this template will render the TitleFieldTemplate with a generated id, if there is a title otherwise nothing is rendered. If you want a different behavior for the rendering of the title of an array field, you can customize this template. If you want a different behavior for the rendering of ALL titles in the Form, see TitleFieldTemplate

import { ArrayFieldTitleTemplateProps, RJSFSchema, titleId } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'array',
items: {
type: 'string',
},
};

function ArrayFieldTitleTemplate(props: ArrayFieldTitleProps) {
const { title, idSchema } = props;
const id = titleId(idSchema);
return <h1 id={id}>{title}</h1>;
}

render(
<Form schema={schema} validator={validator} templates={{ ArrayFieldTitleTemplate }} />,
document.getElementById('app')
);

You also can provide your own template to a uiSchema by specifying a ui:ArrayFieldDescriptionTemplate property.

import { UiSchema } from '@rjsf/utils';

const uiSchema: UiSchema = {
'ui:ArrayFieldTitleTemplate': ArrayFieldTitleTemplate,
};

The following props are passed to each ArrayFieldTitleTemplate:

  • title: The title of the array field being rendered.
  • idSchema: The idSchema of the array field in the hierarchy.
  • schema: The schema object for this array field.
  • uiSchema: The uiSchema object for this array field.
  • required: A boolean value stating if the field is required
  • registry: The registry object.

BaseInputTemplate

The BaseInputTemplate is the template to use to render the basic <input> component for a theme. It is used as the template for rendering many of the <input> based widgets that differ by type and callbacks only. For example, the TextWidget implementation in core is simply a wrapper around BaseInputTemplate that it gets from the registry. Additionally, each theme implements its own version of BaseInputTemplate without needing to provide a different implementation of TextWidget.

If you desire a different implementation for the <input> based widgets, you can customize this template. For instance, say you have a CustomTextInput component that you want to integrate:

import { ChangeEvent, FocusEvent } from 'react';
import { getInputProps, RJSFSchema, BaseInputTemplateProps } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';

import CustomTextInput from '../CustomTextInput';

const schema: RJSFSchema = {
type: 'string',
title: 'My input',
description: 'input description',
};

function BaseInputTemplate(props: BaseInputTemplateProps) {
const {
schema,
id,
options,
label,
value,
type,
placeholder,
required,
disabled,
readonly,
autofocus,
onChange,
onChangeOverride,
onBlur,
onFocus,
rawErrors,
hideError,
uiSchema,
registry,
formContext,
...rest
} = props;
const onTextChange = ({ target: { value: val } }: ChangeEvent<HTMLInputElement>) => {
// Use the options.emptyValue if it is specified and newVal is also an empty string
onChange(val === '' ? options.emptyValue || '' : val);
};
const onTextBlur = ({ target: { value: val } }: FocusEvent<HTMLInputElement>) => onBlur(id, val);
const onTextFocus = ({ target: { value: val } }: FocusEvent<HTMLInputElement>) => onFocus(id, val);

const inputProps = { ...rest, ...getInputProps(schema, type, options) };
const hasError = rawErrors.length > 0 && !hideError;

return (
<CustomTextInput
id={id}
label={label}
value={value}
placeholder={placeholder}
disabled={disabled}
readOnly={readonly}
autoFocus={autofocus}
error={hasError}
errors={hasError ? rawErrors : undefined}
onChange={onChangeOverride || onTextChange}
onBlur={onTextBlur}
onFocus={onTextFocus}
{...inputProps}
/>
);
}

render(
<Form schema={schema} validator={validator} templates={{ BaseInputTemplate }} />,
document.getElementById('app')
);

Sometimes you just need to pass some additional properties to the existing BaseInputTemplate. The way to do this varies based upon whether you are using core or some other theme (such as mui):

import { BaseInputTemplateProps } from '@rjsf/utils';
import { getDefaultRegistry } from '@rjsf/core';
import { Templates } from '@rjsf/mui';

const {
templates: { BaseInputTemplate },
} = getDefaultRegistry(); // To get templates from core
// const { BaseInputTemplate } = Templates; // To get templates from a theme do this

function MyBaseInputTemplate(props: BaseInputTemplateProps) {
const customProps = {};
// get your custom props from where you need to
return <BaseInputTemplate {...props} {...customProps} />;
}

The following props are passed to the BaseInputTemplate:

  • id: The generated id for this widget;
  • schema: The JSONSchema subschema object for this widget;
  • uiSchema: The uiSchema for this widget;
  • value: The current value for this widget;
  • placeholder: The placeholder for the widget, if any;
  • required: The required status of this widget;
  • disabled: A boolean value stating if the widget is disabled;
  • hideError: A boolean value stating if the widget is hiding its errors.
  • readonly: A boolean value stating if the widget is read-only;
  • autofocus: A boolean value stating if the widget should autofocus;
  • label: The computed label for this widget, as a string
  • multiple: A boolean value stating if the widget can accept multiple values;
  • onChange: The value change event handler; call it with the new value every time it changes;
  • onChangeOverride: A BaseInputTemplate implements a default onChange handler that it passes to the HTML input component to handle the ChangeEvent. Sometimes a widget may need to handle the ChangeEvent using custom logic. If that is the case, that widget should provide its own handler via this prop;
  • onKeyChange: The key change event handler (only called for fields with additionalProperties); pass the new value every time it changes;
  • onBlur: The input blur event handler; call it with the widget id and value;
  • onFocus: The input focus event handler; call it with the widget id and value;
  • options: A map of options passed as a prop to the component (see Custom widget options).
  • options.enumOptions: For enum fields, this property contains the list of options for the enum as an array of { label, value } objects. If the enum is defined using the oneOf/anyOf syntax, the entire schema object for each option is appended onto the { schema, label, value } object.
  • formContext: The formContext object that you passed to Form.
  • rawErrors: An array of strings listing all generated error messages from encountered errors for this widget.
  • registry: The registry object

DescriptionFieldTemplate

Each theme implements a DescriptionFieldTemplate used to render the description of a field. If you want to customize how descriptions are rendered you can.

import { DescriptionFieldProps, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'string',
title: 'My input',
description: 'input description',
};

function DescriptionFieldTemplate(props: DescriptionFieldProps) {
const { description, id } = props;
return (
<details id={id}>
<summary>Description</summary>
{description}
</details>
);
}

render(
<Form schema={schema} validator={validator} templates={{ DescriptionFieldTemplate }} />,
document.getElementById('app')
);

The following props are passed to the DescriptionFieldTemplate:

  • description: The description of the field being rendered.
  • id: The id of the field in the hierarchy.
  • schema: The schema object for the field.
  • uiSchema: The uiSchema object for the field.
  • registry: The registry object.

ErrorListTemplate

The ErrorListTemplate is the template that renders the all the errors associated with the fields in the Form, at the top. Each theme implements a ErrorListTemplate used to render its errors using components for the theme's toolkit. If you want to customize how all the errors are rendered you can.

import { ErrorListProps, RJSFValidationError, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'string',
title: 'My input',
description: 'input description',
};

function ErrorListTemplate(props: ErrorListProps) {
const { errors } = props;
return (
<details id={id}>
<summary>Errors</summary>
<ul>
{errors.map((error: RJSFValidationError, i: number) => {
return (
<li key={i} className='error'>
{error.stack}
</li>
);
})}
</ul>
</details>
);
}

render(
<Form schema={schema} validator={validator} templates={{ ErrorListTemplate }} />,
document.getElementById('app')
);

The following props are passed to the ErrorListTemplate:

  • schema: The schema that was passed to Form
  • uiSchema: The uiSchema that was passed to Form
  • formContext: The formContext object that you passed to Form.
  • errors: An array of all errors in this Form.
  • errorSchema: The ErrorSchema constructed by Form

FieldErrorTemplate

The FieldErrorTemplate is the template that renders all the errors associated a single field. If you want to customize how the errors are rendered you can.

import { FieldErrorProps, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'string',
title: 'My input',
description: 'input description',
};

function FieldErrorTemplate(props: FieldErrorProps) {
const { errors } = props;
return (
<details id={id}>
<summary>Errors</summary>
<ul>
{errors.map((error: string, i: number) => {
return (
<li key={i} className='error'>
{error.stack}
</li>
);
})}
</ul>
</details>
);
}

render(
<Form schema={schema} validator={validator} templates={{ FieldErrorTemplate }} />,
document.getElementById('app')
);

The following props are passed to the FieldErrorTemplate:

  • schema: The schema for the field
  • uiSchema: The uiSchema for the field
  • idSchema: An object containing the id for this field & ids for its properties.
  • errors: An array of all errors for this field
  • errorSchema: The ErrorSchema for this field
  • registry: The Registry object

FieldHelpTemplate

The FieldHelpTemplate is the template that renders the help associated a single field. If you want to customize how the help is rendered you can.

import { FieldHelpProps, RJSFSchema, helpId } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'string',
title: 'My input',
description: 'input description',
};

function FieldHelpTemplate(props: FieldHelpProps) {
const { help, idSchema } = props;
const id = helpId(idSchema);
return <aside id={id}>{help}</aside>;
}

render(
<Form schema={schema} validator={validator} templates={{ FieldHelpTemplate }} />,
document.getElementById('app')
);

The following props are passed to the FieldHelpTemplate:

  • schema: The schema for the field
  • uiSchema: The uiSchema for the field
  • idSchema: An object containing the id for this field & ids for its properties.
  • help: The help information to be rendered
  • registry: The Registry object

FieldTemplate

To take control over the inner organization of each field (each form row), you can define a field template for your form.

A field template is basically a React stateless component being passed field-related props, allowing you to structure your form row as you like.

import { FieldTemplateProps, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'string',
};

function CustomFieldTemplate(props: FieldTemplateProps) {
const { id, classNames, style, label, help, required, description, errors, children } = props;
return (
<div className={classNames} style={style}>
<label htmlFor={id}>
{label}
{required ? '*' : null}
</label>
{description}
{children}
{errors}
{help}
</div>
);
}

render(
<Form schema={schema} validator={validator} templates={{ FieldTemplate: CustomFieldTemplate }} />,
document.getElementById('app')
);

You also can provide your own field template to a uiSchema by specifying a ui:FieldTemplate property.

import { UiSchema } from '@rjsf/utils';

const uiSchema: UiSchema = {
'ui:FieldTemplate': CustomFieldTemplate,
};

If you want to handle the rendering of each element yourself, you can use the props rawHelp, rawDescription and rawErrors.

The following props are passed to a custom field template component:

  • id: The id of the field in the hierarchy. You can use it to render a label targeting the wrapped widget.
  • classNames: A string containing the base Bootstrap CSS classes, merged with any custom ones defined in your uiSchema.
  • style: An object containing the StyleHTMLAttributes defined in the uiSchema.
  • label: The computed label for this field, as a string.
  • description: A component instance rendering the field description, if one is defined (this will use any custom DescriptionFieldTemplate defined in the templates passed to the Form).
  • rawDescription: A string containing any ui:description uiSchema directive defined.
  • children: The field or widget component instance for this field row.
  • hideError: A boolean value stating if the field is hiding its errors.
  • errors: A component instance listing any encountered errors for this field.
  • rawErrors: An array of strings listing all generated error messages from encountered errors for this field.
  • help: A component instance rendering any ui:help uiSchema directive defined.
  • rawHelp: A string containing any ui:help uiSchema directive defined. NOTE: rawHelp will be undefined if passed ui:help is a React component instead of a string.
  • hidden: A boolean value stating if the field should be hidden.
  • required: A boolean value stating if the field is required.
  • readonly: A boolean value stating if the field is read-only.
  • hideError: A boolean value stating if the field is hiding its errors
  • disabled: A boolean value stating if the field is disabled.
  • displayLabel: A boolean value stating if the label should be rendered or not. This is useful for nested fields in arrays where you don't want to clutter the UI.
  • schema: The schema object for this field.
  • uiSchema: The uiSchema object for this field.
  • onChange: The value change event handler; Can be called with a new value to change the value for this field.
  • formContext: The formContext object that you passed to Form.
  • formData: The formData for this field.
  • registry: The registry object.

Note: you can only define a single global field template for a form, but you can set individual field templates per property using "ui:FieldTemplate".

ObjectFieldTemplate

import { ObjectFieldTemplateProps, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'object',
title: 'Object title',
description: 'Object description',
properties: {
name: {
type: 'string',
},
age: {
type: 'number',
},
},
};

function ObjectFieldTemplate(props: ObjectFieldTemplateProps) {
return (
<div>
{props.title}
{props.description}
{props.properties.map((element) => (
<div className='property-wrapper'>{element.content}</div>
))}
</div>
);
}

render(
<Form schema={schema} validator={validator} templates={{ ObjectFieldTemplate }} />,
document.getElementById('app')
);

You also can provide your own field template to a uiSchema by specifying a ui:ObjectFieldTemplate property.

import { UiSchema } from '@rjsf/utils';

const uiSchema: UiSchema = {
'ui:ObjectFieldTemplate': ObjectFieldTemplate,
};

Please see the customObject.tsx sample from the playground for a better example.

The following props are passed to each ObjectFieldTemplate as defined by the ObjectFieldTemplateProps in @rjsf/utils:

  • title: A string value containing the title for the object.
  • description: A string value containing the description for the object.
  • disabled: A boolean value stating if the object is disabled.
  • properties: An array of object representing the properties in the object. Each of the properties represent a child with properties described below.
  • onAddClick: (schema: RJSFSchema) => () => void: Returns a function that adds a new property to the object (to be used with additionalProperties)
  • readonly: A boolean value stating if the object is read-only.
  • required: A boolean value stating if the object is required.
  • hideError: A boolean value stating if the field is hiding its errors.
  • schema: The schema object for this object.
  • uiSchema: The uiSchema object for this object field.
  • idSchema: An object containing the id for this object & ids for its properties.
  • errorSchema: The optional validation errors in the form of an ErrorSchema
  • formData: The form data for the object.
  • formContext: The formContext object that you passed to Form.
  • registry: The registry object.

The following props are part of each element in properties:

  • content: The html for the property's content.
  • name: A string representing the property name.
  • disabled: A boolean value stating if the object property is disabled.
  • readonly: A boolean value stating if the property is read-only.
  • hidden: A boolean value stating if the property should be hidden.

Note: Array and object field templates are always rendered inside the FieldTemplate. To fully customize an object field template, you may need to specify both ui:FieldTemplate and ui:ObjectFieldTemplate.

TitleFieldTemplate

Each theme implements a TitleFieldTemplate used to render the title of a field. If you want to customize how titles are rendered you can.

import { RJSFSchema, TitleFieldProps } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'string',
title: 'My input',
description: 'input description',
};

function TitleFieldTemplate(props: TitleFieldProps) {
const { id, required, title } = props;
return (
<header id={id}>
{title}
{required && <mark>*</mark>}
</header>
);
}

render(
<Form schema={schema} validator={validator} templates={{ TitleFieldTemplate }} />,
document.getElementById('app')
);

The following props are passed to each TitleFieldTemplate:

  • id: The id of the field in the hierarchy.
  • title: The title of the field being rendered.
  • schema: The schema object for the field.
  • uiSchema: The uiSchema object for the field.
  • required: A boolean value stating if the field is required
  • registry: The registry object.

UnsupportedFieldTemplate

The UnsupportedField component is used to render a field in the schema is one that is not supported by react-jsonschema-form. If you want to customize how an unsupported field is rendered (perhaps for localization purposes) you can.

import { RJSFSchema, UnsupportedFieldProps } from '@rjsf/utils';
import { FormattedMessage } from 'react-intl';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'invalid',
};

function UnsupportedFieldTemplate(props: UnsupportedFieldProps) {
const { schema, reason } = props;
return (
<div>
<FormattedMessage defaultMessage='Unsupported field schema, reason = {reason}' value={{ reason }} />
<pre>{JSON.stringify(schema, null, 2)}</pre>
</div>
);
}

render(
<Form schema={schema} validator={validator} templates={{ UnsupportedFieldTemplate }} />,
document.getElementById('app')
);

The following props are passed to each UnsupportedFieldTemplate:

  • schema: The schema object for this unsupported field.
  • idSchema: An object containing the id for this unsupported field.
  • reason: The reason why the schema field has an unsupported type.
  • registry: The registry object.

WrapIfAdditionalTemplate

The WrapIfAdditionalTemplate is used by the FieldTemplate to conditionally render additional controls if additionalProperties is present in the schema. You may customize WrapIfAdditionalTemplate if you wish to change the layout or behavior of user-controlled additionalProperties.

import { RJSFSchema, WrapIfAdditionalTemplateProps } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'object',
additionalProperties: true,
};

function WrapIfAdditionalTemplate(props: WrapIfAdditionalTemplateProps) {
const { id, label, onKeyChange, onDropPropertyClick, schema, children, uiSchema, registry, classNames, style } =
props;
const { RemoveButton } = registry.templates.ButtonTemplates;
const additional = ADDITIONAL_PROPERTY_FLAG in schema;

if (!additional) {
return <div>{children}</div>;
}

return (
<div className={classNames} style={style}>
<label label={keyLabel} id={`${id}-key`}>
Custom Field Key
</label>
<input
className='form-control'
type='text'
id={`${id}-key`}
onBlur={function (event) {
onKeyChange(event.target.value);
}}
defaultValue={label}
/>
<div>{children}</div>
<RemoveButton onClick={onDropPropertyClick(label)} uiSchema={uiSchema} />
</div>
);
}

render(
<Form schema={schema} validator={validator} templates={{ WrapIfAdditionalTemplate }} />,
document.getElementById('app')
);

The following props are passed to the WrapIfAdditionalTemplate:

  • children: The children of the component, typically specified by the FieldTemplate.

  • id: The id of the field in the hierarchy. You can use it to render a label targeting the wrapped widget.

  • classNames: A string containing the base Bootstrap CSS classes, merged with any custom ones defined in your uiSchema.

  • style: An object containing the StyleHTMLAttributes defined in the uiSchema.

  • label: The computed label for this field, as a string.

  • required: A boolean value stating if the field is required.

  • readonly: A boolean value stating if the field is read-only.

  • disabled: A boolean value stating if the field is disabled.

  • schema: The schema object for this field.

  • uiSchema: The uiSchema object for this field.

  • onKeyChange: A function that, when called, changes the current property key to the specified value

  • onDropPropertyClick: A function that, when called, removes the key from the formData.

ButtonTemplates

There are several buttons that are potentially rendered in the Form. Each of these buttons have been customized in the themes, and can be customized by you as well. All but one of these buttons (i.e. the SubmitButton) are rendered currently as icons with title text for a description.

Each button template (except for the SubmitButton) accepts, as props, the standard HTML button attributes along with the following:

  • iconType: An alternative specification for the type of the icon button.
  • icon: The name representation or actual react element implementation for the icon.
  • uiSchema: The uiSchema object for this field.
  • registry: The registry object.

AddButton

The AddButton is used to render an add action on a Form for both a new additionalProperties element for an object or a new element in an array. You can customize the AddButton to render something other than the icon button that is provided by a theme as follows:

import React from 'react';
import { IconButtonProps, RJSFSchema } from '@rjsf/utils';
import { FormattedMessage } from 'react-intl';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'string',
};

function AddButton(props: IconButtonProps) {
const { icon, iconType, ...btnProps } = props;
return (
<button {...btnProps}>
{icon} <FormattedMessage defaultMessage='Add' />
</button>
);
}

render(
<Form schema={schema} validator={validator} templates={{ ButtonTemplates: { AddButton } }} />,
document.getElementById('app')
);

MoveDownButton

The MoveDownButton is used to render a move down action on a Form for elements in an array. You can customize the MoveDownButton to render something other than the icon button that is provided by a theme as follows:

import React from 'react';
import { IconButtonProps, RJSFSchema } from '@rjsf/utils';
import { FormattedMessage } from 'react-intl';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'string',
};

function MoveDownButton(props: IconButtonProps) {
const { icon, iconType, ...btnProps } = props;
return (
<button {...btnProps}>
{icon} <FormattedMessage defaultMessage='Move Down' />
</button>
);
}

render(
<Form schema={schema} validator={validator} templates={{ ButtonTemplates: { MoveDownButton } }} />,
document.getElementById('app')
);

MoveUpButton

The MoveUpButton is used to render a move up action on a Form for elements in an array. You can customize the MoveUpButton to render something other than the icon button that is provided by a theme as follows:

import React from 'react';
import { IconButtonProps, RJSFSchema } from '@rjsf/utils';
import { FormattedMessage } from 'react-intl';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'string',
};

function MoveUpButton(props: IconButtonProps) {
const { icon, iconType, ...btnProps } = props;
return (
<button {...btnProps}>
{icon} <FormattedMessage defaultMessage='Move Up' />
</button>
);
}

render(
<Form schema={schema} validator={validator} templates={{ ButtonTemplates: { MoveUpButton } }} />,
document.getElementById('app')
);

RemoveButton

The RemoveButton is used to render a remove action on a Form for both a existing additionalProperties element for an object or an existing element in an array. You can customize the RemoveButton to render something other than the icon button that is provided by a theme as follows:

import React from 'react';
import { IconButtonProps, RJSFSchema } from '@rjsf/utils';
import { FormattedMessage } from 'react-intl';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'string',
};

function RemoveButton(props: IconButtonProps) {
const { icon, iconType, ...btnProps } = props;
return (
<button {...btnProps}>
{icon} <FormattedMessage defaultMessage='Remove' />
</button>
);
}

render(
<Form schema={schema} validator={validator} templates={{ ButtonTemplates: { RemoveButton } }} />,
document.getElementById('app')
);

SubmitButton

The SubmitButton is already very customizable via the UISchemaSubmitButtonOptions capabilities in the uiSchema but it can also be fully customized as you see fit.

NOTE: However you choose to implement this, making it something other than a submit type button may result in the Form not submitting when pressed. You could also choose to provide your own submit button as the children prop of the Form should you so choose.

import React from 'react';
import { getSubmitButtonOptions, RJSFSchema, SubmitButtonProps } from '@rjsf/utils';
import { FormattedMessage } from 'react-intl';
import validator from '@rjsf/validator-ajv8';

const schema: RJSFSchema = {
type: 'string',
};

function SubmitButton(props: SubmitButtonProps) {
const { uiSchema } = props;
const { norender } = getSubmitButtonOptions(uiSchema);
if (norender) {
return null;
}
return (
<button type='submit'>
<FormattedMessage defaultMessage='Okay' />
</button>
);
}

render(
<Form schema={schema} validator={validator} templates={{ ButtonTemplates: { SubmitButton } }} />,
document.getElementById('app')
);

The following prop is passed to a SubmitButton:

  • uiSchema: The uiSchema object for this field, used to extract the UISchemaSubmitButtonOptions.
  • registry: The registry object.