6.x Upgrade Guide
New packages
There are 5 new packages added in RJSF version 6:
@rjsf/daisyui
: This is new theme based on thedaisyui
toolkit@rjsf/mantine
: This is new theme based on themantine
toolkit@rjsf/primereact
: This is a new theme based on thePrimeReact
toolkit@rjsf/react-bootstrap
: This is rename of thebootstrap-4
theme with an upgrade to the latest version ofreact-bootstrap
@rjsf/shadcn
: This is new theme based on theshadcn
toolkit
Breaking changes
CJS build changes
Due to making all of the package.json
files for the @rjsf/*
libraries include "type": "module"
to better support modern ESM
builds, the generation of the Common JS distributions were updated to produce .cjs
files rather than .js
files.
Hopefully this will not cause any issues with existing uses of the libraries. If so, one may need to switch from doing an import
of the CJS build to doing a require()
.
Theme removals
The following themes were removed due to duplication of a framework with a newer theme
bootstrap-4
The older bootstrap-4
theme has been removed in favor of the react-bootstrap
theme
fluent-ui
The older fluent-ui
theme has been removed in favor of the fluentui-rc
theme
material-ui
The older material-ui
theme has been removed in favor of the mui
theme
validator-ajv6
This deprecated validator has been removed. Use the validator-ajv8
.
Theme version support changes
@rjsf/antd
Version 6 is dropping official support for antd
version 4. You must upgrade to version 5.
@rjsf/chakra-ui
Version 6 is dropping official support for @chakra-ui
version 2. You must upgrade to version 3. We are also requiring
chakra-react-select
version >=6 as a result.
@mui version 5 and 6
Version 6 is dropping official support for @mui/material
and @mui/icons-material
versions 5 and 6 due to the adoption
of breaking changes in version 7. You must upgrade to version 7.
@rjsf/semantic-ui DEPRECATED
Version 6 is dropping official support for semantic-ui-react
version 1. You must upgrade to version 2. Also, this theme
is deprecated and will be removed in a future release unless sematic-ui-react
version 3 is released with React 19
support. Although that seems unlikely as no changes have been made to version 3 since December 2023.
Node support
Version 6 is dropping official support for Node 14, 16, and 18 as they are no longer maintained versions.
Please use Node 22 when making any changes to package.json
and package-lock.json
files.
All PR and branch builds are running against Node 20 and 22.
React version
RJSF is no longer actively supporting React version < 18.x. React 18 is officially supported on all the themes.
React 19 support is expected before the end of beta (although several developers have already upgraded with no problems).
formContext BREAKING CHANGES
Removed the unnecessary formContext
property from the following interfaces since it is readily available in the registry
.
If you were using the formContext
in your custom template
, field
or widget
, simply get it from the registry
instead.
Interfaces with formContext
removed:
ErrorListProps
- The properties that are passed to anErrorListTemplate
implementationFieldProps
- The properties that are passed to aField
implementationFieldTemplateProps
- The properties that are passed to aFieldTemplate
implementationArrayFieldTemplateProps
- The properties that are passed to anArrayFieldTemplate
implementationWidgetProps
- The properties that are passed to aWidget
implementation
Fields BREAKING CHANGES
FieldProps.onChange
The onChange
handling for fields has been changed to fix a serious bug related to nearly simultaneous updates losing data.
Previously in 5.x, data change handling worked by passing a complete newFormData
object up to the Form
from the underlying Field
s.
In 6.x, data change handling now works by passing just the changed newValue
for a Field
and the path
array of the Field
within the formData
, with the Form
itself being responsible for injecting the changed data into the formData
.
As a result, the FieldProps
interface was updated with the following breaking change so that custom Field
authors are forced to respond to this update:
// Version 5's `onChange` handler:
/** The field change event handler; called with the updated form data and an optional `ErrorSchema` */
onChange: (newFormData: T | undefined, es?: ErrorSchema<T>, id?: string) => any;
// Version 6's `onChange` handler:
/** The field change event handler; called with the updated field value, the optional change path for the value
* (defaults to an empty array), an optional ErrorSchema and the optional id of the field being changed
*/
onChange: (newValue: T | undefined, path?: (number | string)[], es?: ErrorSchema<T>, id?: string) => void;
In order to support letting the Form
know what the path of the change was, a new path: (number | string)[]
parameter was injected into the handler before the es?: ErrorSchema<T>
parameter.
If you have written a custom Field
that implements merging the new value into the newFormData
, now you just need to pass that value and provide an empty path
array to the onChange
function.
Here is an example of a custom Field
that was updated due to this change:
import { FieldProps } from '@rjsf/utils';
import { getDefaultRegistry } from '@rjsf/core';
const { ArrayField } = getDefaultRegistry().fields;
// Version 5-based custom field
function CustomField(props: FieldProps) {
const {
idSchema: { $id },
formData,
onChange,
} = props;
const changeHandlerFactory = (fieldName: string) => (event: any) => {
onChange({ ...formData, [fieldName]: event.target.value });
};
return (
<>
<h4>Location</h4>
<div>
<label htmlFor={`${$id}-city`}>City</label>
<input
className='form-control'
id={`${$id}-city`}
required={false}
placeholder=''
type='text'
value={formData?.city || ''}
onChange={changeHandlerFactory('city')}
/>
</div>
<div>
<label htmlFor={`${$id}-lat`}>Latitude</label>
<input
className='form-control'
id={`${$id}-lat`}
type='number'
value={formData?.lat || 0}
onChange={changeHandlerFactory('lat')}
/>
</div>
<div>
<label htmlFor={`${$id}-lon`}>Longitude</label>
<input
className='form-control'
id={`${$id}-lon`}
type='number'
value={formData?.lon || 0}
onChange={changeHandlerFactory('lon')}
/>
</div>
</>
);
}
// Version 6-based custom field
function CustomField(props: FieldProps) {
const {
idSchema: { $id },
formData,
onChange,
} = props;
const changeHandlerFactory = (fieldName: string) => (event: any) => {
onChange(event.target.value, [fieldName]);
};
return (
<>
<h4>Location</h4>
<div>
<label htmlFor={`${$id}-city`}>City</label>
<input
className='form-control'
id={`${$id}-city`}
required={false}
placeholder=''
type='text'
value={formData?.city || ''}
onChange={changeHandlerFactory('city')}
/>
</div>
<div>
<label htmlFor={`${$id}-lat`}>Latitude</label>
<input
className='form-control'
id={`${$id}-lat`}
type='number'
value={formData?.lat || 0}
onChange={changeHandlerFactory('lat')}
/>
</div>
<div>
<label htmlFor={`${$id}-lon`}>Longitude</label>
<input
className='form-control'
id={`${$id}-lon`}
type='number'
value={formData?.lon || 0}
onChange={changeHandlerFactory('lon')}
/>
</div>
</>
);
}
The same change also applies to the ErrorSchema
object being passed to the Form
.
Therefore, if your custom Field
also updated the ErrorSchema
to add a new error, now you just need to pass that error as well.
Here is an example of a custom Field
that was updated due to this change:
import { FieldProps } from '@rjsf/utils';
import { getDefaultRegistry } from '@rjsf/core';
const { StringField } = getDefaultRegistry().fields;
// Version 5-based custom field
function StringFieldError(props: FieldProps) {
const onChange = (newFormData: any | undefined, es?: ErrorSchema, id?: string) => {
let raiseError = es;
if (newFormData === 'test') {
raiseError = {
...es,
__errors: ['Value cannot be "test"'],
};
}
props.onChange(newFormData, raiseError, id);
};
return <StringField {...props} onChange={onChange} />;
}
// Version 6-based custom field
function StringFieldError(props: FieldProps) {
const onChange = (newValue: any | undefined, path?: (number | string)[], es?: ErrorSchema, id?: string) => {
let raiseError = es;
if (newValue === 'test') {
raiseError = {
__errors: ['Value cannot be "test"'],
};
}
props.onChange(newValue, path, raiseError, id);
};
return <StringField {...props} onChange={onChange} />;
}
Templates BREAKING CHANGES
ArrayFieldTemplateItemType
The type ArrayFieldTemplateItemType
was deprecated in favor of the ArrayFieldItemTemplateType
type, which matches the type naming pattern properly.
ArrayFieldItemTemplate
The ArrayFieldItemTemplateType
was refactored to extract the following props into out a new ArrayFieldItemButtonsTemplateType
:
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.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
.
A new buttonsProps
prop was added of the type ArrayFieldItemButtonsTemplateType
This new type was then used to create a new ArrayFieldItemButtonsTemplate
in the Registry.templates
.
See ArrayFieldItemButtonTemplate
If you have implemented your own ArrayFieldItemTemplate
or ArrayField
then you will have to account for these changes.
GridTemplate
A new, theme-dependent template GridTemplate
was added to support the new layout feature and must be provided if you are building your own registry.templates
rather than overloading them via the templates
props.
MultiSchemaFieldTemplate
This new template was created to extract styling applied to the MultiSchemaField
component in the @rjsf/core
package.
If you have styled your form using the following classNames and you do NOT use the @rjsf/core
theme, you may need to adjust your styles, as they may have been removed from your theme: panel
, panel-default
, panel-body
, form-group
.
SchemaUtilsType
Five new functions were added to this type, so if you have your own implementation of this type, you will need to add them to yours. The following new functions match the 5 new validator-based utility API functions mentioned below:
findFieldInSchema(path: string | string[], schema: S, formData?: T): FoundFieldType<S>
findSelectedOptionInXxxOf(schema: S, fallbackField: string, xxx: 'anyOf' |
oneOf, formData?: T): S | undefined;
getFromSchema(schema: S, path: string | string[], defaultValue: T): T;
getFromSchema(schema: S, path: string | string[], defaultValue: S): S;
getFromSchema(schema: S, path: string | string[], defaultValue: T | S): S | T;
Removed deprecations
The following deprecations were removed from the code base in v6
FormProps.acceptcharset
The acceptcharset
prop on Form
was removed. Use the acceptCharset
prop instead. I.e.:
<Form acceptCharset='ISO-8859-1' />
getMatchingOption()
The getMatchingOption()
function in @rjsf/utils
was removed. Use the getFirstMatchingOption()
function instead.
I.e.:
import { getFirstMatchingOption, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
// your schema goes here
};
const formData = {
/* your form data goes here */
};
const options: RJSFSchema[] = [
/* your options extracted from the schema go here */
];
const option = getFirstMatchingOption(validator, formData, options, schema);
SchemaUtilsType.getMatchingOption()
The getMatchingOption()
function in the SchemaUtilsType
was removed. Use the getFirstMatchingOption()
funciton on
the type instead. I.e.:
import { createSchemaUtils, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
// your schema goes here
};
const formData = {
/* your form data goes here */
};
const options: RJSFSchema[] = [
/* your options extracted from the schema go here */
];
const schemaUtils = createSchemaUtils(validator, schema);
const option = schemaUtils.getFirstMatchingOption(formData, options);
mergeValidationData()
The mergeValidationData()
function from @rjsf/utils
was removed. Use the validationDataMerge()
function instead.
I.e.:
import { validationDataMerge, ValidationData, ErrorSchema } from '@rjsf/utils';
const validationData: ValidationData = {
errors: [
/* Your validation errors go here */
],
errorSchema: {
/* Your error schema goes here */
},
};
const additionalErrorSchema: ErrorSchema = {
/* Your additional error schema goes here */
};
const merged = validationDataMerge(validationData, additionalErrorSchema);
SchemaUtilsType.mergeValidationData()
The mergeValidationData()
function in the SchemaUtilsType
was removed. Use the standalone validationDataMerge()
function instead. I.e.:
import { toErrorList } from '@rjsf/utils';
const validationData: ValidationData = {
errors: [
/* Your validation errors go here */
],
errorSchema: {
/* Your error schema goes here */
},
};
const additionalErrorSchema: ErrorSchema = {
/* Your additional error schema goes here */
};
const merged = validationDataMerge(validationData, additionalErrorSchema);
ValidatorType.toErrorList()
The toErrorList()
function on the ValidatorType
interface was removed. Use the standalone toErrorList()
function
from @rjsf/utils
instead. I.e.:
import { validationDataMerge, ErrorSchema, RJSFValidationError, toErrorList } from '@rjsf/utils';
const errorSchema: ErrorSchema = {
/* Your error schema goes here */
};
const validationErrors: RJSFValidationError[] = toErrorList(errorSchema);
RJSF_ADDITONAL_PROPERTIES_FLAG
The constant RJSF_ADDITONAL_PROPERTIES_FLAG
was removed from @rjsf/utils
. Use the RJSF_ADDITIONAL_PROPERTIES_FLAG
constant instead. I.e.:
import { RJSF_ADDITIONAL_PROPERTIES_FLAG } from '@rjsf/utils';
UiSchema.classNames
The classNames
notation on UiSchema
was removed. Use the ui:classNames
notation instead. I.e.:
{
"someField": {
"ui:classNames": "someCustomClass"
}
}
schema.enumNames
The custom enumNames
property support on a JSON Schema that RJSF invented has been removed. Please use the UiSchema
replacement, ui:enumNames
instead. I.e.:
import { UiSchema, RJSFSchema } from '@rjsf/utils';
const schema: RJSFSchema = {
type: 'object',
properties: {
attendance: {
title: 'How did you attend the event?',
enum: ['person', 'phone', 'video'],
},
rating: {
title: 'How would you rate this event?',
enum: ['0', '1', '2', '3', '4'],
},
},
};
const uiSchema: UiSchema = {
attendance: {
'ui:enumNames': ['I joined in person', 'I called in using the phone number', 'I joined using the video link'],
},
rating: {
'ui:enumNames': ["I did't like it", 'It was meh', 'It was ok', 'I liked it', 'I loved it'],
},
};
Use the ui:enumNames
in the UiSchema
instead.
Other BREAKING CHANGES
Primitive field handling in oneOf/anyOf schemas
A bug fix was implemented that changes how primitive fields (boolean, string, number, etc.) are handled when switching between oneOf/anyOf schema options with mergeDefaultsIntoFormData: "useDefaultIfFormDataUndefined"
.
Previous (buggy) behavior: Undefined primitive fields were incorrectly set to empty objects {}
when switching between schema variants.
New (correct) behavior: Undefined primitive fields now remain undefined
or receive proper default values according to their type when switching between schema variants.
This change fixes #4709 and was implemented in #4710.
Impact: If your application was incorrectly relying on undefined primitive fields becoming {}
objects, you may need to update your form validation or data processing logic to handle proper primitive values or undefined
instead.
SchemaField removed Bootstrap 3 classes
In fixing #2280, the following Bootstrap 3
classes
(form-group
, has-error
and has-danger
error classes) were removed from the classNames
prop passed down to the
FieldTemplate
. They were instead moved into the core
theme's WrapIfAdditionalTemplate
to ensure that theme was
unchanged.
Additionally, the Bootstrap 3 classes panel
, panel-default
, panel-body
, and form-group
were removed from the
MultiSchemaField
component in the @rjsf/core
package, and moved into the core
theme's MultiSchemaFieldTemplate
to ensure that the theme was unchanged.
As a result, the themes (other than core
) will no longer render these classes.
If you use a non-core
theme and were relying on them for in your application's styling or behavior (via css overrides
perhaps), then you can still use the non-Bootstrap 3
RJSF marker class (see below) or your specific theme's error classes.
prefixed RJSF template and field marker classes
Many of the core
RJSF templates and field implementations that are shared across all themes were updated to add the
rjsf-
prefix to the marker classes that are being added to the rendered HTML. The following table highlights the old
and new marker classes. If you were relying on any of these classes, simply do a rename:
old marker class | new marker class |
---|---|
field | rjsf-field |
field-<schema.type> | rjsf-field-<schema.type> |
field-array | rjsf-field-array |
field-array-of-<schema.type> | rjsf-field-array-of-<schema.type> |
field-array-fixed-items | rjsf-field-array-fixed-items |
field-error | rjsf-field-error |
field-hidden | rjsf-field-hidden |
array-item | rjsf-array-item |
config-error | rjsf-config-error |
array-item-add | rjsf-array-item-add |
array-item-copy | rjsf-array-item-copy |
array-item-move-down | rjsf-array-item-move-down |
array-item-move-up | rjsf-array-item-move-up |
array-item-remove | rjsf-array-item-remove |
object-property-expand | rjsf-object-property-expand |
object-property-remove | rjsf-object-property-remove |
optionsList
The generics ordering on the optionsList()
function was changed from <S, T, F>
to <T, S, F>
to be consistent with the rest of the APIs.
New Features
New types
The following new types were added to @rjsf/utils
:
ArrayFieldItemTemplateType
: The properties of each element in the ArrayFieldTemplateProps.items array. NOTE:ArrayFieldTemplateItemType
is an alias to this typeFoundFieldType
: The interface for the return value of thefindFieldInSchema
functionGridTemplateProps
: The properties that are passed to aGridTemplate
MultiSchemaFieldTemplateProps
: The properties that are passed to aMultiSchemaFieldTemplate
TestIdShape
: The interface for the test ID proxy objects that are returned by thegetTestId
utility function
New non-validator utility functions
Three new and three formerly internally private utility functions are available in @rjsf/utils
:
buttonId<T>(id: IdSchema<T> | string, btn: 'add' | 'copy' | 'moveDown' | 'moveUp' | 'remove')
: Generates consistent ids for RJSF buttonsgetTestIds(): TestIdShape
: Returns an object of test IDs that can only be used in test mode, helpful for writing unit tests for React componentshashObject(object: unknown): string
: Stringifies anobject
and returns the hash of the resulting stringhashString(string: string): string
: Hashes a string into hex formatlookupFromFormContext<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(regOrFc: Registry<T, S, F> | Registry<T, S, F>['formContext'], toLookup: string, fallback?: unknown)
: Given a React JSON Schema Form registry or formContext object, return the value associated withtoLookup
sortedJSONStringify(object: unknown): string
: Stringifies anobject
, sorts object fields in consistent order before stringifying it.
New validator-based utility functions
Three new validator-based utility functions are available in @rjsf/utils
:
findFieldInSchema<T = undefined, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(validator: ValidatorType<T, S, F>, rootSchema: S, path: string | string[], schema: S, formData?: T, experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>): FoundFieldType<S>
: Finds the field specified by thepath
within the root or recursedschema
findSelectedOptionInXxxOf<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(validator: ValidatorType<T, S, F>, rootSchema: S, schema: S, fallbackField: string,xxx: 'anyOf' | 'oneOf', formData?: T, experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>): S | undefined
: Finds the option that matches the selector field in theschema
or undefined if nothing is selectedgetFromSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(validator: ValidatorType<T, S, F>, rootSchema: S, schema: S, path: string | string[], defaultValue: T | S, experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>): T | S
: Helper that acts like lodash'sget
but additionally retrieves$ref
s as needed to get the path for schemas
Dynamic UI Schema for Array Items
RJSF 6.x introduces a new feature that allows dynamic UI schema generation for array items.
The items
property in a uiSchema
can now accept a function that returns a UI schema based on the array item's data, index, and form context.
const uiSchema: UiSchema = {
myArrayField: {
items: (itemData, index, formContext) => {
// Return different UI schemas based on item data
if (itemData?.type === 'special') {
return { 'ui:widget': 'textarea' };
}
return { 'ui:widget': 'text' };
},
},
};
This feature is fully backward compatible - existing forms using object-based uiSchema.items
will continue to work without changes.
See the Dynamic UI Schema Examples documentation for comprehensive examples and usage patterns.