Custom Templates
This is an advanced feature that lets you customize even more aspects of the form:
Custom Field | Custom Template | Custom Widget | |
---|---|---|---|
What it does | Overrides all behaviour | Overrides just the layout (not behaviour) | Overrides just the input box (not layout, labels, or help, or validation) |
Usage | Global or per-field | Global or per-field | Global 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 |
Documentation | Custom Fields | See documentation below | Custom 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 Type | UiSchema name | Origin |
---|---|---|---|
ArrayFieldTemplate | ArrayFieldTemplateProps | ui:ArrayFieldTemplate | Formerly Form.ArrayFieldTemplate or Registry.ArrayFieldTemplate |
ArrayFieldDescriptionTemplate* | ArrayFieldDescriptionProps | ui:ArrayFieldDescriptionTemplate | Formerly part of @rjsf/core ArrayField, refactored as a template, used in all ArrayFieldTemplate implementations |
ArrayFieldItemTemplate* | ArrayFieldTemplateItemType | ui:ArrayFieldItemTemplate | Formerly an internal class for ArrayFieldTemplate s in all themes, refactored as a template in each theme, used in all ArrayFieldTemplate implementations |
ArrayFieldTitleTemplate* | ArrayFieldTitleProps | ui:ArrayFieldTitleTemplate | Formerly part of @rjsf/core ArrayField, refactored as a template, used in all ArrayFieldTemplate implementations. |
BaseInputTemplate* | WidgetProps | ui:BaseInputTemplate | Formerly a widget in @rjsf.core moved to templates and newly implemented in each theme to maximize code reuse. |
DescriptionFieldTemplate* | DescriptionFieldProps | ui:DescriptionFieldTemplate | Formerly a field in @rjsf.core moved to templates with the Template suffix. Previously implemented in each theme. |
ErrorListTemplate* | ErrorListProps | ui:ErrorListTemplate | Formerly Form.ErrorList moved to templates with the Templates suffix. Previously implemented in each theme. |
FieldErrorTemplate* | FieldErrorProps | ui:FieldErrorTemplate | Formerly internal ErrorList component accessible only to SchemaField |
FieldHelpTemplate* | FieldHelpProps | ui:FieldHelpTemplate | Formerly internal Help component accessible only to SchemaField |
FieldTemplate | FieldTemplateProps | ui:FieldTemplate | Formerly Form.FieldTemplate or Registry.FieldTemplate |
ObjectFieldTemplate | ObjectFieldTemplateProps | ui:ObjectFieldTemplate | Formerly Form.ObjectFieldTemplate or Registry.ObjectFieldTemplate |
TitleFieldTemplate* | TitleFieldProps | ui:TitleFieldTemplate | Formerly a field in @rjsf.core moved to templates with the Template suffix. Previously implemented in each theme. |
UnsupportedFieldTemplate* | UnsupportedFieldProps | ui:UnsupportedFieldTemplate | Formerly a field in @rjsf.core moved to templates with the Template suffix. |
WrapIfAdditionalTemplate* | WrapIfAdditionalTemplateProps | ui:WrapIfAdditionalTemplate | Formerly an internal component in @rjsf.core . Previously implemented in most themes. |
ButtonTemplates.AddButton* | IconButtonProps | n/a | Formerly an internal implementation in each theme |
ButtonTemplates.MoveDownButton* | IconButtonProps | n/a | Formerly an internal implementation in each theme |
ButtonTemplates.MoveUpButton* | IconButtonProps | n/a | Formerly an internal implementation in each theme |
ButtonTemplates.RemoveButton* | IconButtonProps | n/a | Formerly an internal implementation in each theme |
ButtonTemplates.SubmitButton* | SubmitButtonProps | n/a | Formerly 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 propertiesitems
: 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
: TheformContext
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 anErrorSchema
rawErrors
: An array of strings listing all generated error messages from encountered errors for this widgetregistry
: Theregistry
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 initems
.key
: A stable, unique key for the array item.onAddIndexClick: (index) => (event?) => void
: Returns a function that adds a new item atindex
.onDropIndexClick: (index) => (event?) => void
: Returns a function that removes the item atindex
.onReorderClick: (index, newIndex) => (event?) => void
: Returns a function that swaps the items atindex
withnewIndex
.readonly
: A boolean value stating if the array item is read-only.uiSchema
: The uiSchema object for this array item.registry
: Theregistry
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
andui: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
: Theregistry
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 initems
.totalItems
: A number stating the total numberitems
in the array.key
: A stable, unique key for the array item.onAddIndexClick: (index) => (event?) => void
: Returns a function that adds a new item atindex
.onDropIndexClick: (index) => (event?) => void
: Returns a function that removes the item atindex
.onReorderClick: (index, newIndex) => (event?) => void
: Returns a function that swaps the items atindex
withnewIndex
.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
: Theregistry
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 requiredregistry
: Theregistry
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')
);
Wrapping BaseInputTemplate to customize it
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 stringmultiple
: 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
: ABaseInputTemplate
implements a defaultonChange
handler that it passes to the HTML input component to handle theChangeEvent
. Sometimes a widget may need to handle theChangeEvent
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 withadditionalProperties
); 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
: TheformContext
object that you passed toForm
.rawErrors
: An array of strings listing all generated error messages from encountered errors for this widget.registry
: Theregistry
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
: Theregistry
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 toForm
uiSchema
: The uiSchema that was passed toForm
formContext
: TheformContext
object that you passed toForm
.errors
: An array of all errors in thisForm
.errorSchema
: TheErrorSchema
constructed byForm
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 fielduiSchema
: The uiSchema for the fieldidSchema
: An object containing the id for this field & ids for its properties.errors
: An array of all errors for this fielderrorSchema
: TheErrorSchema
for this fieldregistry
: TheRegistry
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 fielduiSchema
: The uiSchema for the fieldidSchema
: An object containing the id for this field & ids for its properties.help
: The help information to be renderedregistry
: TheRegistry
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 theStyleHTMLAttributes
defined in theuiSchema
.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 customDescriptionFieldTemplate
defined in thetemplates
passed to theForm
).rawDescription
: A string containing anyui:description
uiSchema directive defined.children
: The field or widget component instance for this field row.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 anyui:help
uiSchema directive defined.rawHelp
: A string containing anyui:help
uiSchema directive defined. NOTE:rawHelp
will beundefined
if passedui: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 errorsdisabled
: 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
: TheformContext
object that you passed toForm
.formData
: The formData for this field.registry
: Theregistry
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 anErrorSchema
formData
: The form data for the object.formContext
: TheformContext
object that you passed to Form.registry
: Theregistry
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
andui: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 requiredregistry
: Theregistry
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
: Theregistry
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 theFieldTemplate
.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 theStyleHTMLAttributes
defined in theuiSchema
.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 valueonDropPropertyClick
: 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
: Theregistry
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
typebutton
may result in theForm
not submitting when pressed. You could also choose to provide your own submit button as the children prop of theForm
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 theUISchemaSubmitButtonOptions
.registry
: Theregistry
object.