Technical Documentation: rjsf-team/react-jsonschema-form
ℹ️ Provenance: Multi-Tier Ingestion · CodeWiki Reference
Overview (`README.md`)
Supported Themes
- Ant Design v5
- Bootstrap v3
- Chakra UI v3
- Daisy UI v5
- Fluent UI v9
- Mantine
- Material UI v7
- React-Bootstrap (Bootstrap v5)
- Semantic UI v2
- Shad CN
API Libraries
Documentation
Read our documentation, powered by Docusaurus.
Live Playground
A live playground is hosted on GitHub Pages.
Contributing
Read our contributors' guide to get started.
Credits
Testing powered by BrowserStack
Overview (`docs/README.md`)
docs (DEPRECATED)
The react-jsonschema-form documentation has been moved here
Overview (`packages/antd/README.md`)
Table of Contents
About The Project
Ant Design theme, fields and widgets for react-jsonschema-form.
Built With
Getting Started
Prerequisites
antd >= 5@ant-design/icons >= 5dayjs >= 1.8.0@rjsf/core >= 6@rjsf/utils >= 6@rjsf/validator-ajv8 >= 6
npm install antd @ant-design/icons dayjs @rjsf/core @rjsf/utils @rjsf/validator-ajv8Installation
npm install @rjsf/antdUsage
import Form from '@rjsf/antd';or
import { withTheme } from '@rjsf/core';
import { Theme as AntDTheme } from '@rjsf/antd';
// Make modifications to the theme with your own fields and widgets
const Form = withTheme(AntDTheme);Roadmap
See the general open issues.
Contributing
Read our contributors' guide to get started.
Contact
rjsf team: https://github.com/orgs/rjsf-team/people
GitHub repository: https://github.com/rjsf-team/react-jsonschema-form
Overview (`packages/chakra-ui/README.md`)
Table of Contents
- Table of Contents
- About The Project
- Getting Started
- Usage
- Optional Chakra UI Theme properties
- Roadmap
- Contributing
- Contact
About The Project
Exports chakra-ui theme, fields and widgets for react-jsonschema-form.
Built With
Getting Started
Prerequisites
@chakra-ui/react >= 3chakra-react-select >= 6@rjsf/core >= 6@rjsf/utils >= 6@rjsf/validator-ajv8 >= 6
Refer to the rjsf installation guide and chakra-ui installation guide and for more details.
Installation
yarn add @chakra-ui/react chakra-react-select @rjsf/core @rjsf/utils @rjsf/validator-ajv8Usage
yarn add @rjsf/chakra-uiimport Form from '@rjsf/chakra-ui';or
import { withTheme } from '@rjsf/core';
import { Theme as ChakraUITheme } from '@rjsf/chakra-ui';
// Make modifications to the theme with your own fields and widgets
const Form = withTheme(ChakraUITheme);Optional Chakra UI Theme properties
- To pass additional properties to widgets, see this guide.
You can use ChakraProvider, to customize the components at a theme level.
And, uiSchema allows for the use of a "chakra" "ui:option" to customize the styling of the form widgets.
Custom Chakra uiSchema Chakra Property
{
"ui:options": {
"chakra": {
"p": "1rem",
"color": "blue.200",
"sx": {
"margin": "0 auto"
}
}
}
}It accepts the theme accessible style props provided by Chakra and Emotion.
Roadmap
See the open issues for a list of proposed features (and known issues).
Contributing
Read our contributors' guide to get started.
Contact
rjsf team: https://github.com/orgs/rjsf-team/people
GitHub repository: https://github.com/rjsf-team/react-jsonschema-form
Overview (`packages/core/README.md`)
Table of Contents
About The Project
Core logic and classic Bootstrap 3 theme for react-jsonschema-form.
Built With
Getting Started
Prerequisites
Bootstrap 3
To use the default Bootstrap 3 theme, add a Bootstrap 3 CSS tag to your HTML page:
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />Installation
npm install @rjsf/coreUsage
import Form from '@rjsf/core';Roadmap
See the general open issues.
Contributing
Read our contributors' guide to get started.
Contact
rjsf team: https://github.com/orgs/rjsf-team/people
GitHub repository: https://github.com/rjsf-team/react-jsonschema-form
Overview (`packages/daisyui/README.md`)
@rjsf/daisyui
A DaisyUI theme for react-jsonschema-form.
This package integrates DaisyUI, Tailwind CSS, and RJSF to provide a modern, customizable form experience.
Screenshots
Features
- Complete DaisyUI styling for all RJSF form elements
- Responsive design with mobile-friendly layouts
- Connected card styling for nested elements and arrays
- Consistent visual hierarchy for complex forms
- Support for all RJSF field types including:
- Text inputs with proper styling and validation states
- Select dropdowns with customizable option rendering
- Checkboxes and radio buttons with optimized layouts
- Arrays with add/remove/reorder functionality
- Objects with proper nesting and visual hierarchy
- Date/time inputs with cross-browser compatibility
- Support for custom themes via DaisyUI's theme system
- Accessible form components following WAI-ARIA practices
Getting Started
Prerequisites
daisyui >= 5@fluentui/react-icons >= 2@fluentui/react-migration-v0-v9 >= 9@rjsf/core >= 6@rjsf/utils >= 6@rjsf/validator-ajv8 >= 6
Installation
npm install @rjsf/daisyui @rjsf/core @rjsf/utils @rjsf/validator-ajv8 tailwindcss daisyuiUsage
import { Form } from '@rjsf/daisyui';
import validator from '@rjsf/validator-ajv8';
function App() {
return (
<Form schema={schema} uiSchema={uiSchema} validator={validator} onChange={console.log} onSubmit={console.log} />
);
}Theme Customization
The form components use DaisyUI's theme system. You can customize the theme by adding DaisyUI theme classes to your HTML:
<html data-theme="light">
</html>For dynamic theme switching, you can change the data-theme attribute in your application code.
Tailwind Configuration
Make sure your src/index.css includes the DaisyUI plugin:
@import 'tailwindcss';
@source "../node_modules/@rjsf/daisyui";
@plugin "daisyui" {
themes: all;
}It's necessary to explicitely include the library as a source, as tailwindcss by default ignores everything in .gitignore
Customization
Grid Layout
The DaisyUI theme supports the standard RJSF layout grid system. You can use grid layouts by incorporating the LayoutGridField in your UI schema:
/* Detailed source-code truncated for AI context efficiency. */The DaisyUI theme uses a flexible grid system based on Tailwind CSS's flex utilities. This grid layout integrates with the standard RJSF layout system, providing a consistent experience across all themes.
Theme Configuration
DaisyUI itself provides a variety of themes. To use a specific theme, add the data-theme attribute to your root element:
<div data-theme='dark'>
<Form schema={schema} validator={validator} />
</div>You can also dynamically change themes in your application:
import { useState } from 'react';
import { Form } from '@rjsf/daisyui';
import validator from '@rjsf/validator-ajv8';
function App() {
const [theme, setTheme] = useState('light');
return (
<div data-theme={theme}>
<select value={theme} onChange={(e) => setTheme(e.target.value)}>
<option value='light'>Light</option>
<option value='dark'>Dark</option>
<option value='cupcake'>Cupcake</option>
<option value='cyberpunk'>Cyberpunk</option>
<option value='synthwave'>Synthwave</option>
{/* Add more themes as needed */}
</select>
<Form schema={schema} validator={validator} />
</div>
);
}Development
To develop locally:
# Clone the repository
git clone https://github.com/rjsf-team/react-jsonschema-form.git
cd react-jsonschema-form
# Install dependencies
npm install
# Build packages
npm run build
# Run playground
npm run start:playgroundTo test the DaisyUI theme specifically, select it from the themes dropdown in the playground.
License
Apache-2.0
Overview (`packages/docs/README.md`)
react-jsonschema-form Documentation
This website is built using Docusaurus 2, a modern static website generator.
Installation
$ pnpm installLocal Development
$ pnpm startThis command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
Build
$ pnpm buildThis command generates static content into the build directory and can be served using any static contents hosting service.
Deployment
Deployment is handled automatically by GitHub pages.
Overview (`packages/fluentui-rc/README.md`)
Table of Contents
About The Project
Fluent UI React Components (v9) theme, fields and widgets for react-jsonschema-form.
Built With
Getting Started
Prerequisites
@fluentui/react-components >= 9@fluentui/react-icons >= 2@fluentui/react-migration-v0-v9 >= 9@rjsf/core >= 6@rjsf/utils >= 6@rjsf/validator-ajv8 >= 6
yarn add @fluentui/react-components @fluentui/react-icons @fluentui/react-migration-v0-v9 @rjsf/core @rjsf/utils @rjsf/validator-ajv8Installation
yarn add @rjsf/fluentui-rcUsage
import Form from '@rjsf/fluentui-rc';or
import { withTheme } from '@rjsf/core';
import { Theme as FluentUIRCTheme } from '@rjsf/fluentui-rc';
// Make modifications to the theme with your own fields and widgets
const Form = withTheme(FluentUIRCTheme);Roadmap
See the open issues for a list of proposed features (and known issues).
Contributing
Read our contributors' guide to get started.
Contact
rjsf team: https://github.com/orgs/rjsf-team/people
GitHub repository: https://github.com/rjsf-team/react-jsonschema-form
Overview (`packages/mantine/README.md`)
Table of Contents
- Table of Contents
- About The Project
- Getting Started
- Usage
- Optional Mantine Theme properties
- Roadmap
- Contributing
- Contact
About The Project
Mantine theme, fields and widgets for react-jsonschema-form.
Built With
Getting Started
- See the getting started guide on Mantine documentation.
Prerequisites
@mantine/core >= 8@mantine/hooks >= 8@mantine/dates >= 8dayjs >= 1.8.0@rjsf/core >= 6.0.0
npm install @mantine/core @mantine/hooks @mantine/dates dayjs @rjsf/coreInstallation
npm install @rjsf/mantineUsage
import Form from '@rjsf/mantine';or
import { withTheme } from '@rjsf/core';
import { Theme as MantineTheme } from '@rjsf/mantine';
// Make modifications to the theme with your own fields and widgets
const Form = withTheme(MantineTheme);Optional Mantine Theme properties
- To pass additional properties to widgets, see this guide.
Mantine Widget Optional Properties
- Mantine props for CheckboxWidget
- Mantine props for ColorWidget
- Mantine props for DateWidget
- Mantine props for DateTimeWidget
- Mantine props for PasswordWidget
- Mantine props for RadioWidget
- Mantine props for RangeWidget
- Mantine props for SelectWidget
- Mantine props for UpDownWidget
- Mantine props for TextWidget
- Mantine props for TextAreaWidget
- Mantine props for TimeWidget
Roadmap
See the open issues for a list of proposed features (and known issues).
Contributing
Read our contributors' guide to get started.
Contact
rjsf team: https://github.com/orgs/rjsf-team/people
GitHub repository: https://github.com/rjsf-team/react-jsonschema-form
Overview (`packages/mui/README.md`)
Table of Contents
About The Project
Exports MUI version 5 theme, fields, and widgets for react-jsonschema-form.
Built With
Getting Started
Prerequisites
NOTE: Material UI 7 requires React 18, so you will need to upgrade
@mui/material >= 7@mui/icons-material >= 7@emotion/react >= 11@emotion/styled >= 11@rjsf/core >= 6@rjsf/utils >= 6@rjsf/validator-ajv8 >= 6
yarn add @mui/material @mui/icons-material @emotion/react @emotion/styled @rjsf/core @rjsf/utils @rjsf/validator-ajv8Installation
yarn add @rjsf/muiUsage
Material UI version 7
import Form from '@rjsf/mui';or
import { withTheme } from '@rjsf/core';
import { Theme } from '@rjsf/mui';
// Make modifications to the theme with your own fields and widgets
const Form = withTheme(Theme);Customizing MUI-specific props
You can pass MUI-specific props (like sx, rjsfSlotProps, variant, etc.) directly to any MUI component rendered by a Template or Widget via ui:options in the uiSchema.
"myField": {
"ui:options": {
"mui": {
"variant": "filled",
"sx": {
"backgroundColor": "background.paper"
},
"rjsfSlotProps": {
"input": {
"endAdornment": "kg"
}
}
}
}
}For more details on available properties and rjsfSlotProps targets, see the Material UI Customization Documentation.
Roadmap
See the open issues for a list of proposed features (and known issues).
Contributing
Read our contributors' guide to get started.
Contact
rjsf team: https://github.com/orgs/rjsf-team/people
GitHub repository: https://github.com/rjsf-team/react-jsonschema-form
Overview (`packages/primereact/README.md`)
Table of Contents
About The Project
PrimeReact theme, fields, and widgets for react-jsonschema-form.
Built With
Getting Started
Prerequisites
primereact >= 8.0.0primeicons >= 6.0.0@rjsf/core >= 6@rjsf/utils >= 6@rjsf/validator-ajv8 >= 6
npm install primereact primeicons @rjsf/coreInstallation
npm install @rjsf/primereactUsage
import Form from '@rjsf/primereact';or
import { withTheme } from '@rjsf/core';
import { Theme as PrimeReactTheme } from '@rjsf/primereact';
// Customize the theme with your own fields and widgets
const Form = withTheme(PrimeReactTheme);Roadmap
See the general open issues.
Contributing
Read our contributors' guide to get started.
Contact
rjsf team: https://github.com/orgs/rjsf-team/people
GitHub
build-shield: https://github.com/rjsf-team/react-jsonschema-form/workflows/CI/badge.svg
Overview (`packages/react-bootstrap/README.md`)
Table of Contents
About The Project
Exports react-bootstrap theme, fields and widgets for react-jsonschema-form.
Built With
Getting Started
Prerequisites
react-bootstrap >= 2.0.0@rjsf/core >= 6@rjsf/utils >= 6@rjsf/validator-ajv8 >= 6
yarn add react-bootstrap @rjsf/core @rjsf/utils @rjsf/validator-ajv8Installation
yarn add @rjsf/react-bootstrapUsage
import Form from 'packages/react-bootstrap';or
import { withTheme } from '@rjsf/core';
import { Theme as BootstrapTheme } from 'packages/react-bootstrap';
const Form = withTheme(BootstrapTheme);Contributing
Read our contributors' guide to get started.
Contact
rjsf team: https://github.com/orgs/rjsf-team/people
GitHub repository: https://github.com/rjsf-team/react-jsonschema-form
Overview (`packages/semantic-ui/README.md`)
Table of Contents
- Table of Contents
- About The Project
- Getting Started
- Usage
- Optional Semantic UI Theme properties
- Roadmap
- Contributing
- Contact
About The Project
Exports semantic-ui theme, fields and widgets for react-jsonschema-form.
Built With
Getting Started
- See the getting started guide on react-semantic-ui.
Prerequisites
@semantic-ui-react >= 2@semantic-ui-css >= 2(default theme for semantic-ui); see theming guide if you wish to customize@rjsf/core >= 6@rjsf/utils >= 6@rjsf/validator-ajv8 >= 6
yarn add semantic-ui-css semantic-ui-react @rjsf/coreInstallation
yarn add @rjsf/semantic-uiUsage
import Form from '@rjsf/semantic-ui';or
import { withTheme } from '@rjsf/core';
import { Theme as SemanticUITheme } from '@rjsf/semantic-ui';
// Make modifications to the theme with your own fields and widgets
const Form = withTheme(SemanticUITheme);Optional Semantic UI Theme properties
- To pass additional properties to widgets, see this guide.
Semantic Widget Optional Properties
- Semantic props for TextWidget
- Semantic props for CheckboxWidget
- Semantic props for SelectWidget
- Semantic props for RangeWidget
- Semantic props for RadioWidget
- Semantic props for PasswordWidget
- Semantic props for UpDownWidget
- Semantic props for TextAreaWidget
Custom Semantic Widget Properties
Below are the current default options for all widgets:
{
"ui:options": {
"semantic": {
"fluid": true,
"inverted": false,
"errorOptions": {
"size": "small",
"pointing": "above"
}
}
}
}Roadmap
See the open issues for a list of proposed features (and known issues).
Contributing
Read our contributors' guide to get started.
Contact
rjsf team: https://github.com/orgs/rjsf-team/people
GitHub repository: https://github.com/rjsf-team/react-jsonschema-form
Overview (`packages/shadcn/README.md`)
Table of Contents
About The Project
Exports shadcn theme, fields and widgets for react-jsonschema-form.
Built With
Getting Started
Prerequisites
@rjsf/core >= 6@rjsf/utils >= 6@rjsf/validator-ajv8 >= 6
yarn add @rjsf/core @rjsf/utils @rjsf/validator-ajv8Installation
yarn add @rjsf/shadcnUsage
import Form from '@rjsf/shadcn';or
import {withTheme} from '@rjsf/core';
import {Theme as shadcnTheme} from '@rjsf/shadcn';
const Form = withTheme(shadcnTheme);Theming
Using Tailwind
Follow shadCN installation guide here for your application
The color of the RJSF will automatically apply with your shadCN config.
Tailwind v3
Add the following line to your tailwind.config.ts
content: [
"./src/**/*.{html,js}",
"node_modules/@rjsf/shadcn/src/**/*.{js,ts,jsx,tsx,mdx}" // Add this line
],Tailwind v4
Add the following line to your equivalent global.css
@source "../node_modules/@rjsf/shadcn";Not using Tailwind
Use the theme on demo site
A prebuilt stylesheet for each bundled theme is included in the npm package. Simply do
import '@rjsf/shadcn/dist/[theme].css';
e.g:
import '@rjsf/shadcn/dist/default.css';Note that these stylesheets are complete Tailwind builds and include Tailwind's preflight reset, so importing one
will also restyle the rest of your page. If your application already builds Tailwind, use the
Using Tailwind section above instead.
Supported themes are:
- default
- amethyst-haze
- caffeine
- claude
- clean-slate
- neo-brutalism
- pastel-dreams
- soft-pop
- vercel
Coloring
- Generate a theme from official shadCN site
or tweakcn - Navigate to
packages/shadcn/src/css, create a new file called [your-theme].css - Replace the base layer code with your new color
- Follow the next section to build your CSS file
Build your CSS file
If you are not using tailwind but still wants to use this theme, you can follow these steps:
- Clone the repository
cd packages/shadcn
npm i
npm run build:css- Include the built
dist/[your-theme].cssin your application
Dark mode (Tailwind only)
Check out this section by shadCN
RTL (Tailwind only)
Installation
npm install @radix-ui/react-direction --saveImplementation
Wrap your layout with DirectionProvider:
tsximport {DirectionProvider as RadixDirectionProvider} from '@radix-ui/react-direction; function Layout({children, direction}) { return ( <RadixDirectionProvider dir={direction}> {children} </RadixDirectionProvider> ); }Set HTML direction attribute:
html<html dir="rtl" lang="en">You can refer to
direction-context.tsx,direction-provider.tsxandrtl-toggle.tsxfrom demo repository for
implementation.
Updating to latest shadCN version
- Simply copy the shadcn components into shadcn/src/components/ui and rebuilt the packages or using the shadcn CLI at
the root level with the components.json - For RTL version, you might need component from here
by nahasco - Fancy multi-select
Contributing
Read our contributors' guide to get started.
Contact
rjsf team: https://github.com/orgs/rjsf-team/people
GitHub
build-shield: https://github.com/rjsf-team/react-jsonschema-form/workflows/CI/badge.svg
Overview (`packages/snapshot-tests/README.md`)
Table of Contents
About The Project
Package with snapshot test suits for testing themes for react-jsonschema-form.
Getting Started
Installation
npm install @rjsf/snapshot-testsUsage
import { arrayTests } from '@rjsf/snapshot-tests'; // OR
// import { formTests } from '@rjsf/snapshot-tests';
// import { gridTests } from '@rjsf/snapshot-tests';
// import { objectTests } from '@rjsf/snapshot-tests';
import Form from '../src';
arrayTests(Form); // OR
// formTests(Form);
// gridTests(Form);
// objectTests(Form);Roadmap
See the general open issues.
Contributing
Read our contributors' guide to get started.
Contact
rjsf team: https://github.com/orgs/rjsf-team/people
GitHub repository: https://github.com/rjsf-team/react-jsonschema-form
Overview (`packages/utils/README.md`)
Table of Contents
About The Project
Exports utils functions for react-jsonschema-form.
Built With
Getting Started
Installation
yarn add @rjsf/utilsUsage
import * as Utils from '@rjsf/utils';Documentation
Utility function documentation
Roadmap
See the open issues for a list of proposed features (and known issues).
Contributing
Read our contributors' guide to get started.
Contact
rjsf team: https://github.com/orgs/rjsf-team/people
GitHub repository: https://github.com/rjsf-team/react-jsonschema-form
Overview (`packages/validator-ajv8/README.md`)
Table of Contents
About The Project
Exports validator-ajv8 plugin for react-jsonschema-form.
Built With
Getting Started
Prerequisites
React JsonSchema Form Utils
@rjsf/utils >= 5.0.0
yarn add @rjsf/coreInstallation
yarn add @rjsf/validator-ajv8Usage
import { RJSFSchema } from 'packages/utils/dist/index';
import Form from 'packages/core/dist/index';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'string',
};
<Form schema={schema} validator={validator} />;or, using a more complex example using custom validator with custom formats
import { RJSFSchema } from '@rjsf/utils';
import Form from '@rjsf/core';
import { customizeValidator } from '@rjsf/validator-ajv8';
const customFormats = {
'phone-us': /\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{4}$/,
};
const validator = customizeValidator({
customFormats,
});
const schema: RJSFSchema = {
type: 'string',
format: 'phone-us',
};
<Form schema={schema} validator={validator} />;or, using a more complex example using a custom with additional meta schema
import { RJSFSchema } from '@rjsf/utils';
import Form from '@rjsf/core';
import { customizeValidator } from '@rjsf/validator-ajv8';
const metaSchemaDraft06 = require('ajv/lib/refs/json-schema-draft-06.json');
const validator = customizeValidator({
additionalMetaSchemas: [metaSchemaDraft06],
});
const schema: RJSFSchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
type: 'string',
};
<Form schema={schema} validator={validator} />;or, using a more complex example using custom validator config override options
import { RJSFSchema } from '@rjsf/utils';
import Form from '@rjsf/core';
import { customizeValidator } from '@rjsf/validator-ajv8';
const validator = customizeValidator({
ajvOptionsOverrides: {
$data: true,
verbose: true,
},
});
const schema: RJSFSchema = {
type: 'string',
};
<Form schema={schema} validator={validator} />;or, using a more complex example using ajv-formats custom format options.
import { RJSFSchema } from '@rjsf/utils';
import Form from '@rjsf/core';
import { customizeValidator } from '@rjsf/validator-ajv8';
const validator = customizeValidator({
ajvFormatOptions: {
keywords: true,
formats: ['date', 'time'],
},
});
const schema: RJSFSchema = {
type: 'string',
};
<Form schema={schema} validator={validator} />;Finally, you can combine both additional meta schemas, custom formats, custom validator config override options and ajv-formats custom format options.
import { RJSFSchema } from '@rjsf/utils';
import Form from '@rjsf/core';
import { customizeValidator } from '@rjsf/validator-ajv8';
const metaSchemaDraft06 = require('ajv/lib/refs/json-schema-draft-06.json');
const customFormats = {
'phone-us': /\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{4}$/,
};
const validator = customizeValidator({
additionalMetaSchemas: [metaSchemaDraft06],
customFormats,
ajvOptionsOverrides: {
$data: true,
verbose: true,
},
ajvFormatOptions: {
keywords: true,
formats: ['date', 'time'],
},
});
const schema: RJSFSchema = {
$schema: 'http://json-schema.org/draft-06/schema#',
type: 'string',
format: 'phone-us',
};
<Form schema={schema} validator={validator} />;Roadmap
See the open issues for a list of proposed features (and known issues).
Contributing
Read our contributors' guide to get started.
Contact
rjsf team: https://github.com/orgs/rjsf-team/people
GitHub repository: https://github.com/rjsf-team/react-jsonschema-form
Overview (`packages/validator-ata/README.md`)
Table of Contents
About
@rjsf/validator-ata plugs ata-validator into react-jsonschema-form as a drop-in alternative to @rjsf/validator-ajv8. The public API mirrors validator-ajv8 so swapping is a one-line change in the validator import. Error format, custom-format hook, custom validation, and error transformation all work the same way.
ata is a JSON Schema validator that targets Draft 2020-12 (98.5% spec compliance, 95.3% schemasafe pass rate) and is Standard Schema compliant. Its differentiators relative to AJV: pattern checks are RE2-backed (no ReDoS surface), and schemas can be compiled at build time for environments where bundle size or CSP restricts runtime codegen.
Installation
npm install @rjsf/validator-ataata-validator is a dependency of this package and is installed with it.
Usage
import Form from '@rjsf/core';
import validator from '@rjsf/validator-ata';
<Form schema={schema} validator={validator} />;Customization
import { customizeValidator } from '@rjsf/validator-ata';
const validator = customizeValidator({
customFormats: {
'phone-us': /\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{4}$/,
'area-code': /\d{3}/,
},
ataOptionsOverrides: {
verbose: true,
},
});customizeValidator accepts:
customFormats— same shape asvalidator-ajv8. Values may be aRegExp, an anchored regex source string, or a(value: string) => booleanpredicate.ataOptionsOverrides— plainata-validatoroptions spread on top of the defaults; use this to flipcoerceTypes,removeAdditional,verbose, orabortEarly.additionalMetaSchemas— extra schemas registered viaValidator#addSchemafor cross-schema$refresolution.extenderFn— hook applied against a freshly-builtValidator(e.g. for adding additional formats or schemas in one place).suppressDuplicateFiltering— passthrough to the RJSF error processor; same semantics as invalidator-ajv8.
A Localizer may be supplied as the second argument. ata error objects use the same field names as AJV (keyword, instancePath, schemaPath, params, message, parentSchema), so localizers that mutate message in place port across without changes. The pre-quote dance that the AJV validator runs against ajv-i18n is intentionally not replicated here — ata's error params are frozen, and the existing locale catalogues for AJV are not portable to ata's keyword set.
Differences from validator-ajv8
The ValidatorType contract is identical, and the shared @rjsf/utils schema test suite passes against this validator with the deltas below. Behavior outside of this list mirrors validator-ajv8.
- Precompiled validators are supported. See Precompiled validators in the docs.
ajvOptionsOverrides,ajvFormatOptions,AjvClasshave no equivalents and are intentionally not accepted.ataOptionsOverridesreplaces the first; built-in formats are always installed and don't require an opt-in flag.isValidandrawValidationdeep-cloneformDatabefore passing it to ata. ata's default-applier writesdefaultvalues into the input object during validation, while AJV treats validation as a pure operation. The clone preserves the AJV contract RJSF expects when probing data through repeatedisValidcalls (oneOf/anyOf option resolution).- Custom-keyword extensions (e.g.
ajv-errors,ajv-merge-patch) have no ata-side counterpart yet. Schemas using these keywords will validate (ata silently ignores unknown keywords) but the extension semantics are not applied.
Contributing
See the monorepo CONTRIBUTING.md. Issues and PRs welcome on either the validator package or ata-validator itself.
Overview (`packages/validator-cfworker/README.md`)
@rjsf/validator-cfworker
@rjsf/validator-cfworker is an additional validator option for CSP-constrained RJSF users.
It uses @cfworker/json-schema to interpret schemas without eval or new Function, and defaults to JSON Schema draft 2020-12.
It is not an AJV replacement. Choose it when an eval-free runtime is more important than AJV-specific keywords, extensions, localization, or code generation.
import Form from '@rjsf/core';
import validator from '@rjsf/validator-cfworker';
export default function Example() {
return <Form schema={{ type: 'string' }} validator={validator} />;
}Behavior
- Implements RJSF's
ValidatorType<T, S, F>interface. - Normalizes
undefinedbefore validation: undefined object members are omitted sorequirederrors surface, while undefined array entries becomenull. - Caches schema-bound engine instances by schema
$id(or the RJSF schema hash) and refreshes them when the schema or root schema changes. - Supports
customValidate,transformErrors, custom formats, duplicateanyOf/oneOffiltering, and the RJSFcoloranddata-urlformats. - Supports draft 4, draft 7, draft 2019-09, and draft 2020-12 through the
draftcustomization option; the default is draft 2020-12.
import { customizeValidator } from '@rjsf/validator-cfworker';
const validator = customizeValidator({
draft: '2020-12',
shortCircuit: false,
customFormats: {
'phone-us': /\(?\d{3}\)?[\s-]?\d{3}[\s-]?\d{4}$/,
},
});Unsupported-keyword matrix
Unknown keywords are annotations to the underlying engine, so unsupported extensions are not validation constraints.
| Keyword or extension | Status | Notes |
|---|---|---|
$dynamicRef / $dynamicAnchor |
Unsupported | Tracked upstream in cfworker/json-schema#150. |
AJV $data references |
Unsupported | AJV-specific extension; use literal schema values. |
OpenAPI discriminator |
Unsupported | Use standard oneOf constraints without discriminator semantics. |
errorMessage from ajv-errors |
Unsupported | Use RJSF's transformErrors hook instead. |
Precompiled-validator mode is intentionally outside this initial package. Runtime error messages also differ from AJV, and there is no ajv-i18n equivalent.
Upstream state and provenance
This package is ported from glama-ai/rjsf-validator-cfworker, whose structure was intentionally kept compatible with RJSF.
The original MIT copyright and license are preserved in LICENSE; the RJSF integration and subsequent changes are distributed under the monorepo's Apache-2.0 license.
The underlying @cfworker/json-schema package's latest release is from January 2025. Its tracker includes open correctness reports for duplicate schema URIs (#335) and additionalProperties behavior (#336), as well as the $dynamicRef gap above.
This wrapper's per-schema cache avoids repeat registration on RJSF's isValid path, but it does not change the upstream engine's other semantics.
The package is therefore presented as an additional option for CSP-constrained users.
Index (`docs/index.md`)
react-jsonschema-form
The react-jsonschema-form docs have been moved here.
Packages Docs Docs 01 Quickstart (`packages/docs/docs/01-quickstart.md`)
Quickstart
Let's walk through setup of a form after installing the dependency properly.
NOTE: As of version 5, the Form now requires you to provide a validator implementation. We recommend the one from @rjsf/validator-ajv8.
Form schema
First, specify a schema using the JSON Schema specification. The below schema renders a single string field:
import Form from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'Test form',
type: 'string',
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));You can also render an object with multiple fields with the below schema:
import Form from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'Test form',
type: 'object',
properties: {
name: {
type: 'string',
},
age: {
type: 'number',
},
},
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));For more information and examples of JSON Schema properties that this library supports, see Using JSON Schema.
Form uiSchema
The uiSchema is used to add more customization to the form's look and feel. Use the classNames
attribute of the uiSchema to add a custom CSS class name to the form:
import Form from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'Test form',
type: 'string',
};
const uiSchema: UiSchema = {
'ui:classNames': 'custom-css-class',
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));To customize object fields in the uiSchema, the structure of the
uiSchema should be {key: value}, where key is the property key and value is an
object with the uiSchema configuration for that particular property. For example:
import Form from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'Test form',
type: 'object',
properties: {
name: {
type: 'string',
},
age: {
type: 'number',
},
},
};
const uiSchema: UiSchema = {
name: {
'ui:classNames': 'custom-class-name',
},
age: {
'ui:classNames': 'custom-class-age',
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));Form initialization
Often you'll want to prefill a form with existing data; this is done by passing a formData prop object matching the schema:
import Form from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
title: {
type: 'string',
},
done: {
type: 'boolean',
},
},
};
const formData = {
title: 'First task',
done: true,
};
render(<Form schema={schema} formData={formData} validator={validator} />, document.getElementById('app'));Note: If your form has a single field, pass a single value to
formData. ex:formData="Charlie"
WARNING: If you have situations where your parent component can re-render, make sure you listen to the
onChangeevent and update the data you pass to theformDataattribute.
Form event handlers
You can use event handlers such as onChange, onError, onSubmit, onFocus, and onBlur on the <Form /> component; see the Form Props Reference for more details.
Controlled component
By default, <Form /> is an uncontrolled component. To make it a controlled component, use theonChange and formData props as in the below example:
import Form from '@rjsf/core';
import validator from '@rjsf/validator-ajv8';
const App = () => {
const [formData, setFormData] = React.useState(null);
return (
<Form
schema={{ type: 'string' }}
formData={formData}
onChange={(e) => setFormData(e.formData)}
validator={validator}
/>
);
};
render(<App />, document.getElementById('app'));Packages Docs Docs Advanced Customization Index (`packages/docs/docs/advanced-customization/index.mdx`)
title: Advanced Customization
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Docs Api Reference Index (`packages/docs/docs/api-reference/index.mdx`)
title: API Reference
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Docs Json Schema Index (`packages/docs/docs/json-schema/index.mdx`)
title: JSON Schema
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Docs Migration Guides Index (`packages/docs/docs/migration-guides/index.mdx`)
title: Migration Guides
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Docs Usage Index (`packages/docs/docs/usage/index.mdx`)
title: Usage and Customization
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Versioned Docs Version 3.2.1 00 Quickstart (`packages/docs/versioned_docs/version-3.2.1/00-quickstart.md`)
Quickstart
Let's walk through setup of a form after installing the dependency properly.
Form schema
First, specify a schema using the JSON Schema specification. The below schema renders a single string field:
const schema = {
title: "Test form",
type: "string"
};
render((
<Form schema={schema} />
), document.getElementById("app"));You can also render an object with multiple fields with the below schema:
const schema = {
title: "Test form",
type: "object",
properties: {
name: {
type: "string"
},
age: {
type: "number"
}
}
};
render((
<Form schema={schema} />
), document.getElementById("app"));For more information and examples of JSON Schema properties that this library supports, see Using JSON Schema.
Form uiSchema
The uiSchema is used to add more customization to the form's look and feel. Use the classNames
attribute of the uiSchema to add a custom CSS class name to the form:
const schema = {
title: "Test form",
type: "string"
};
const uiSchema = {
classNames: "custom-css-class"
};
render((
<Form schema={schema} uiSchema={uiSchema} />
), document.getElementById("app"));To customize object fields in the uiSchema, the structure of the
uiSchema should be {key: value}, where key is the property key and value is an
object with the uiSchema configuration for that particular property. For example:
const schema = {
title: "Test form",
type: "object",
properties: {
name: {
type: "string"
},
age: {
type: "number"
}
}
};
const uiSchema = {
name: {
classNames: "custom-class-name"
},
age: {
classNames: "custom-class-age"
}
}
render((
<Form schema={schema} />
), document.getElementById("app"));Form initialization
Often you'll want to prefill a form with existing data; this is done by passing a formData prop object matching the schema:
const schema = {
type: "object",
properties: {
title: {
type: "string"
},
done: {
type: "boolean"
}
}
};
const formData = {
title: "First task",
done: true
};
render((
<Form schema={schema}
formData={formData} />
), document.getElementById("app"));Note: If your form has a single field, pass a single value to
formData. ex:formData="Charlie"
WARNING: If you have situations where your parent component can re-render, make sure you listen to the
onChangeevent and update the data you pass to theformDataattribute.
Form event handlers
You can use event handlers such as onChange, onError, onSubmit, onFocus, and onBlur on the <Form /> component; see the Form Props Reference for more details.
Controlled component
By default, <Form /> is an uncontrolled component. To make it a controlled component, use theonChange and formData props as in the below example:
const App = () => {
const [formData, setFormData] = React.useState(null);
return (<Form
schema={{type: "string"}}
formData={formData}
onChange={e => setFormData(e.formData)}
/>);
};
render((
<App />
), document.getElementById("app"));Packages Docs Versioned Docs Version 4.2.3 00 Quickstart (`packages/docs/versioned_docs/version-4.2.3/00-quickstart.md`)
Quickstart
Let's walk through setup of a form after installing the dependency properly.
Form schema
First, specify a schema using the JSON Schema specification. The below schema renders a single string field:
const schema = {
title: "Test form",
type: "string"
};
render((
<Form schema={schema} />
), document.getElementById("app"));You can also render an object with multiple fields with the below schema:
const schema = {
title: "Test form",
type: "object",
properties: {
name: {
type: "string"
},
age: {
type: "number"
}
}
};
render((
<Form schema={schema} />
), document.getElementById("app"));For more information and examples of JSON Schema properties that this library supports, see Using JSON Schema.
Form uiSchema
The uiSchema is used to add more customization to the form's look and feel. Use the classNames
attribute of the uiSchema to add a custom CSS class name to the form:
const schema = {
title: "Test form",
type: "string"
};
const uiSchema = {
classNames: "custom-css-class"
};
render((
<Form schema={schema} uiSchema={uiSchema} />
), document.getElementById("app"));To customize object fields in the uiSchema, the structure of the
uiSchema should be {key: value}, where key is the property key and value is an
object with the uiSchema configuration for that particular property. For example:
const schema = {
title: "Test form",
type: "object",
properties: {
name: {
type: "string"
},
age: {
type: "number"
}
}
};
const uiSchema = {
name: {
classNames: "custom-class-name"
},
age: {
classNames: "custom-class-age"
}
}
render((
<Form schema={schema} />
), document.getElementById("app"));Form initialization
Often you'll want to prefill a form with existing data; this is done by passing a formData prop object matching the schema:
const schema = {
type: "object",
properties: {
title: {
type: "string"
},
done: {
type: "boolean"
}
}
};
const formData = {
title: "First task",
done: true
};
render((
<Form schema={schema}
formData={formData} />
), document.getElementById("app"));Note: If your form has a single field, pass a single value to
formData. ex:formData="Charlie"
WARNING: If you have situations where your parent component can re-render, make sure you listen to the
onChangeevent and update the data you pass to theformDataattribute.
Form event handlers
You can use event handlers such as onChange, onError, onSubmit, onFocus, and onBlur on the <Form /> component; see the Form Props Reference for more details.
Controlled component
By default, <Form /> is an uncontrolled component. To make it a controlled component, use theonChange and formData props as in the below example:
const App = () => {
const [formData, setFormData] = React.useState(null);
return (<Form
schema={{type: "string"}}
formData={formData}
onChange={e => setFormData(e.formData)}
/>);
};
render((
<App />
), document.getElementById("app"));Packages Docs Versioned Docs Version 5.24.10 01 Quickstart (`packages/docs/versioned_docs/version-5.24.10/01-quickstart.md`)
Quickstart
Let's walk through setup of a form after installing the dependency properly.
NOTE: As of version 5, the Form now requires you to provide a validator implementation. We recommend the one from @rjsf/validator-ajv8.
Form schema
First, specify a schema using the JSON Schema specification. The below schema renders a single string field:
import Form from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'Test form',
type: 'string',
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));You can also render an object with multiple fields with the below schema:
import Form from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'Test form',
type: 'object',
properties: {
name: {
type: 'string',
},
age: {
type: 'number',
},
},
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));For more information and examples of JSON Schema properties that this library supports, see Using JSON Schema.
Form uiSchema
The uiSchema is used to add more customization to the form's look and feel. Use the classNames
attribute of the uiSchema to add a custom CSS class name to the form:
import Form from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'Test form',
type: 'string',
};
const uiSchema: UiSchema = {
'ui:classNames': 'custom-css-class',
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));To customize object fields in the uiSchema, the structure of the
uiSchema should be {key: value}, where key is the property key and value is an
object with the uiSchema configuration for that particular property. For example:
import Form from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'Test form',
type: 'object',
properties: {
name: {
type: 'string',
},
age: {
type: 'number',
},
},
};
const uiSchema: UiSchema = {
name: {
'ui:classNames': 'custom-class-name',
},
age: {
'ui:classNames': 'custom-class-age',
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));Form initialization
Often you'll want to prefill a form with existing data; this is done by passing a formData prop object matching the schema:
import Form from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
title: {
type: 'string',
},
done: {
type: 'boolean',
},
},
};
const formData = {
title: 'First task',
done: true,
};
render(<Form schema={schema} formData={formData} validator={validator} />, document.getElementById('app'));Note: If your form has a single field, pass a single value to
formData. ex:formData="Charlie"
WARNING: If you have situations where your parent component can re-render, make sure you listen to the
onChangeevent and update the data you pass to theformDataattribute.
Form event handlers
You can use event handlers such as onChange, onError, onSubmit, onFocus, and onBlur on the <Form /> component; see the Form Props Reference for more details.
Controlled component
By default, <Form /> is an uncontrolled component. To make it a controlled component, use theonChange and formData props as in the below example:
import Form from '@rjsf/core';
import validator from '@rjsf/validator-ajv8';
const App = () => {
const [formData, setFormData] = React.useState(null);
return (
<Form
schema={{ type: 'string' }}
formData={formData}
onChange={(e) => setFormData(e.formData)}
validator={validator}
/>
);
};
render(<App />, document.getElementById('app'));Packages Docs Versioned Docs Version 3.2.1 Advanced Customization Index (`packages/docs/versioned_docs/version-3.2.1/advanced-customization/index.mdx`)
title: Advanced Customization
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Versioned Docs Version 3.2.1 Api Reference Index (`packages/docs/versioned_docs/version-3.2.1/api-reference/index.mdx`)
title: API Reference
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Versioned Docs Version 3.2.1 Usage Index (`packages/docs/versioned_docs/version-3.2.1/usage/index.mdx`)
title: Usage and Customization
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Versioned Docs Version 4.2.3 Advanced Customization Index (`packages/docs/versioned_docs/version-4.2.3/advanced-customization/index.mdx`)
title: Advanced Customization
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Versioned Docs Version 4.2.3 Api Reference Index (`packages/docs/versioned_docs/version-4.2.3/api-reference/index.mdx`)
title: API Reference
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Versioned Docs Version 4.2.3 Usage Index (`packages/docs/versioned_docs/version-4.2.3/usage/index.mdx`)
title: Usage and Customization
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Versioned Docs Version 5.24.10 Advanced Customization Index (`packages/docs/versioned_docs/version-5.24.10/advanced-customization/index.mdx`)
title: Advanced Customization
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Versioned Docs Version 5.24.10 Api Reference Index (`packages/docs/versioned_docs/version-5.24.10/api-reference/index.mdx`)
title: API Reference
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Versioned Docs Version 5.24.10 Json Schema Index (`packages/docs/versioned_docs/version-5.24.10/json-schema/index.mdx`)
title: JSON Schema
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Versioned Docs Version 5.24.10 Migration Guides Index (`packages/docs/versioned_docs/version-5.24.10/migration-guides/index.mdx`)
title: Migration Guides
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Versioned Docs Version 5.24.10 Usage Index (`packages/docs/versioned_docs/version-5.24.10/usage/index.mdx`)
title: Usage and Customization
import DocCardList from '@theme/DocCardList';
{frontMatter.description}
Packages Docs Package.Json (`packages/docs/package.json`)
{
"name": "@rjsf/docs",
"version": "6.11.0",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
"start": "docusaurus start",
"build": "docusaurus build",
"swizzle": "docusaurus swizzle",
"deploy": "docusaurus deploy",
"clear": "docusaurus clear",
"serve": "docusaurus serve",
"write-translations": "docusaurus write-translations",
"write-heading-ids": "docusaurus write-heading-ids",
"typecheck": "tsc",
"precommit": "lint-staged",
"cs-check": "oxfmt --check "src//*.{ts,tsx}"",
"cs-format": "oxfmt "src//.{ts,tsx}""
},
"lint-staged": {
"src/**/.{ts,tsx}": [
"oxfmt"
]
},
"dependencies": {
"@docusaurus/core": "^3.10.2",
"@docusaurus/preset-classic": "^3.10.2",
"@mdx-js/react": "^3.1.1",
"prism-react-renderer": "^2.4.1"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "^3.10.2",
"@docusaurus/plugin-content-docs": "^3.10.2",
"@docusaurus/types": "^3.10.2",
"@tsconfig/docusaurus": "^2.0.9"
},
"browserslist": {
"production": [
">0.5%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"engines": {
"node": ">=20"
}
}
Packages Docs Tsconfig.Json (`packages/docs/tsconfig.json`)
{
// This file is not used in compilation. It is here just for a nice editor experience.
"extends": "@tsconfig/docusaurus/tsconfig.json",
"compilerOptions": {
"resolveJsonModule": true
}
}
Packages Docs Docs 00 Introduction (`packages/docs/docs/00-introduction.mdx`)
id: intro title: Introduction slug: /
react-jsonschema-form
A simple React component capable of building HTML forms out of a JSON schema.
A live playground is hosted on GitHub Pages:
Philosophy
react-jsonschema-form is meant to automatically generate a React form based on a JSON Schema. If you want to generate a form for any data, sight unseen, simply given a JSON schema, react-jsonschema-form may be for you. If you have a priori knowledge of your data and want a toolkit for generating forms for it, you might look elsewhere.
react-jsonschema-form also comes with tools such as uiSchema and other form props to customize the look and feel of the form beyond the default themes.
Installation
First install the dependencies from npm, along with a validator implementation (such as @rjsf/validator-ajv8):
$ npm install @rjsf/core @rjsf/utils @rjsf/validator-ajv8 --saveThen import the dependencies as follows:
import Form from '@rjsf/core';
import validator from '@rjsf/validator-ajv8';Our latest version requires React 16+.
Usage
import Form from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'Todo',
type: 'object',
required: ['title'],
properties: {
title: { type: 'string', title: 'Title', default: 'A new task' },
done: { type: 'boolean', title: 'Done?', default: false },
},
};
const log = (type) => console.log.bind(console, type);
render(
<Form
schema={schema}
validator={validator}
onChange={log('changed')}
onSubmit={log('submitted')}
onError={log('errors')}
/>,
document.getElementById('app')
);Theming
For more information on what themes we support, see Using Themes.
License
Apache 2
Credits
| This project initially started as a mozilla-services project. | |
|---|---|
| Testing is powered by BrowserStack. | |
| Deploy Previews are provided by Netlify. |
Who uses react-jsonschema-form?
- ...
Add your own company / organization by making a pull request.
Packages Docs Docs Contributing (`packages/docs/docs/contributing.md`)
Contributing
Development server
We are using Vite to power our playground, which caches all the built @rjsf/* distributions.
In order to test the playground locally after a new clone or fresh pull from main, run the following from the root directory of the monorepo:
pnpm install
pnpm run build
cd packages/playground
pnpm startThis will start the live development server showcasing components at localhost:8080.
Whenever you make changes to source code, stop the running playground and return to the root directory and rerun pnpm run build.
Thanks to nx caching, this should only rebuild what is necessary.
After the build is complete, return to the root of the playground and restart the server via pnpm start.
First time step
If this is the first time you have cloned the repo, run the pnpm run prepare script that will set up husky to provide a git precommit hook that will format and lint any code you have added to a PR.
Optional development process
With the large number of packages, sometimes running pnpm run build or pnpm start from the root directory will overwhelm an underpowered computer.
If that is the situation for you, you can instead use pnpm run build-serial to build the packages one at a time instead of all at once.
Also, if you are only working on one package, you can pnpm run build and pnpm run test from within the subdirectory.
Finally, you can simply pnpm start inside of the playground directory to test changes if you have already built all of your packages, without needing to watch all of the packages via the root directory pnpm start.
Troubleshooting build failures
Sometimes your local builds fail and you can't figure out why. This is most likely to happen after rebase to main due
to package.json changes upstream. There are two commands you can use to (hopefully) get your environment back to a
working state. Try running the following two commands:
pnpm run refresh-node-modules
pnpm run clean-buildThe first command will delete all of the node_modules directories in the environment and then rerun pnpm install.
The second command cleans up the typescript build cache files before retrying the build.
Worst case scenario when neither of those commands work, try running pnpm run nuke-build-env and then rerun the two commands.
Cloud builds
When building in environments with limited memory, such as Netlify, it's recommended to use pnpm run build-serial that builds the packages serially.
Coding style
All the JavaScript/Typescript code in this project conforms to the prettier coding style.
Code is automatically prettified upon commit using precommit hooks, assuming you followed the First time step above.
You can also run pnpm cs-format within any package directory you are changing.
Documentation
We use Docusaurus to build our documentation. To run documentation locally, run:
cd packages/docs
pnpm startDocumentation will be served on localhost:3000.
Tests
You can run all tests from the root directory OR from packages subdirectory using the following command:
pnpm run testSnapshot testing
All the themes, including core use snapshot testing (NOTE: core also has extensive non-snapshot tests).
The source-code of these snapshot tests reside in the core package in the testSnap directory and are shared with all the themes.
In order to support the various themes, the code for the tests are actually functions that take two parameters:
Form: ComponentType<FormProps> - The component from the theme implementation[customOptions]: { [key: string]: TestRendererOptions } - an optional map ofreact-test-rendererTestRendererOptionsimplementations that some themes need to be able properly run
There are functions in the testSnap directory: arrayTests, formTests and objectTests, each with its own definition of customOptions
Each theme will basically run these functions by creating a Xxx.test.tsx file (where Xxx is Array, Form or Object) that looks like the following:
import { arrayTests } from '@rjsf/snapshot-tests'; // OR
// import { formTests } from '@rjsf/snapshot-tests';
// import { objectTests } from '@rjsf/snapshot-tests';
import Form from '../src';
arrayTests(Form); // OR
// formTests(Form);
// objectTests(Form);Anytime you add a new feature, be sure to update the appropriate xxxTests() function in the testSnap directory and do pnpm run test from the root directory to update all the snapshots.
If you add a theme-only feature, it is ok to update the appropriate Xxx.test.tsx file to add (or update) the theme-specific describe() block.
For example:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import { arrayTests } from '@rjsf/snapshot-tests';
import Form from '../src';
formTests(Form);
describe('Theme specific tests', () => {
it('test a theme-specific option', () => {
const schema: RJSFSchema = {
type: 'object',
properties: {
name: {
type: 'string',
},
},
};
const uiSchema: UiSchema = {
// Enable the theme specific feature
};
const tree = renderer.create(<Form schema={schema} uiSchema={uiSchema} validator={validator} />).toJSON();
expect(tree).toMatchSnapshot();
});
});See the antd Form.test.tsx for a specific example of this.
Code coverage
Code coverage reports are currently available only for the @rjsf/core theme package.
They are generated using nyc each time the pnpm test-coverage script is run.
The full report can be seen by opening ./coverage/lcov-report/index.html.
Utils and validator-ajv8 code coverage
100% code coverage is required by the @rjsf/utils and @rjsf/validator-ajv8 tests.
If you make changes to those libraries, you will have to maintain that coverage, otherwise the tests will fail.
NOTE: All three of these directories share the same tests for verifying
validatorbased APIs. See the documentation in thegetTestValidator()functions for more information.
Releasing
To release, go to the main branch (NOT a fork) and then create a new branch with the version number (with an rc prefix instead of v).
For instance if you are about to create the new 6.100.10 branch, then you would run the following commands:
git checkout -b rc6.100.10
pnpm exec nx release version --git-tag
git commit -m "Releasing 6.100.10"
git push
pnpm run update-version-tagsMake sure you use semver for version numbering when selecting the version.
The pnpm exec nx release version --git-tag command will update the package*.json files and create a new version tag.
Committing and pushing the branch will allow you to create the PR on GitHub.
The pnpm run update-version-tags will push the tags up to GitHub.
Then, make a PR to main. Merge the PR into main -- make sure you use "merge commit", not squash and merge, so that
the original commit where the tag was based on is still present in the main branch.
Then, create a release in the GitHub "Releases" tab, select the new tag that you have added,
and add a description of the changes in the new release. You can copy
the latest changelog entry in CHANGELOG.md to make the release notes, and update as necessary.
This will trigger a GitHub Actions pipeline that will build and publish all packages to npm.
The package is published through an automation token belonging to the
rjsf-bot user on npm. This token
is stored as the NPM_TOKEN secret on GitHub Actions.
Releasing docs
Docs are automatically published to GitHub Pages when the main branch is updated.
We are currently in the process of automatically configuring versionable documentation on our new docs site.
Releasing the playground
The playground automatically gets deployed from GitHub Pages.
If you need to manually publish the latest playground to https://rjsf-team.github.io/react-jsonschema-form/, though, run:
cd packages/playground
pnpm run publish-to-gh-pagesReleasing a new package
Publishing a new @rjsf/* package requires additional setup. The package must first be published locally, then in the NPM web app, you must set up "Trusted Publishing" so future releases can be published via GitHub Actions. The steps to accomplish this are:
- Create the new release as described above. Existing packages will be published, but the jobs to publish new package(s) will fail.
- Locally, check out the release tag (e.g.
git checkout v6.8.0). You may need togit fetch --tags. Make sure yourgit statusis clean. cd packages/new-packagepnpm login(login to an account with RJSF publishing privileges)pnpm publish --no-git-checks.
The new package will be released. Then, set up Trusted Publishing:
- Navigate to the new package in NPM (e.g.
https://www.npmjs.com/package/@rjsf/new-package) - Go to Settings -> Trusted Publisher -> GitHub Actions
- Set up the fields to match an existing package (e.g. look at
@rjsf/core).- Organization or user:
rjsf-team - Repository:
react-jsonschema-form - Workflow filename:
release.yml - Allow
npm publish
- Organization or user:
Packages Docs Versioned Sidebars Version 3.2.1 Sidebars.Json (`packages/docs/versioned_sidebars/version-3.2.1-sidebars.json`)
{
"docs": [
{
"type": "autogenerated",
"dirName": "."
}
]
}
Packages Docs Versioned Sidebars Version 4.2.3 Sidebars.Json (`packages/docs/versioned_sidebars/version-4.2.3-sidebars.json`)
{
"docs": [
{
"type": "autogenerated",
"dirName": "."
}
]
}
Packages Docs Versioned Sidebars Version 5.24.10 Sidebars.Json (`packages/docs/versioned_sidebars/version-5.24.10-sidebars.json`)
{
"docs": [
{
"type": "autogenerated",
"dirName": "."
}
]
}
Packages Docs Docs Advanced Customization Custom Templates (`packages/docs/docs/advanced-customization/custom-templates.md`)
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 and patternProperties 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 | ArrayFieldItemTemplateProps | ui:ArrayFieldItemTemplate | Formerly an internal class for ArrayFieldTemplates in all themes, refactored as a template in each theme, used in all ArrayFieldTemplate implementations |
| ArrayFieldItemButtonsTemplate | ArrayFieldItemButtonsTemplateProps | ui:ArrayFieldItemButonsTemplate | Formerly an internal class for ArrayFieldItemTemplates in all themes, refactored as a template in the core, used in all ArrayFieldItemTemplate 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. |
| CyclicSchemaExpandTemplate | CyclicSchemaExpandProps | ui:CyclicSchemaExpandTemplate | Added in RJSF v6 to support circular $ref cycle detection |
| 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. |
| FallbackFieldTemplate | FallbackFieldTemplateProps | ui:FallbackFieldTemplate | Added in RJSF v6 |
| 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 |
| GridTemplate | GridTemplateProps | ui:GridTemplate | Theme dependent implementations of a Grid element for either rows or columns |
| MultiSchemaFieldTemplate | MultiSchemaFieldTemplateProps | ui:MultiSchemaFieldTemplate | Formerly part of @rjsf/core MultiSchemaField`, refactored as a template |
| ObjectFieldTemplate | ObjectFieldTemplateProps | ui:ObjectFieldTemplate | Formerly Form.ObjectFieldTemplate or Registry.ObjectFieldTemplate |
| OptionalDataControlsTemplate | OptionalDataControlsTemplateProps | ui:OptionalDataControlsTemplate | New feature in V6 |
| 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 |
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 with your Component :
import { UiSchema } from '@rjsf/utils';
import ArrayFieldTemplate from './ArrayFieldTemplate';
const uiSchema: UiSchema = {
'ui:ArrayFieldTemplate': ArrayFieldTemplate,
};or a string value from the Registry :
import { UiSchema } from '@rjsf/utils';
const uiSchema: UiSchema = {
'ui:ArrayFieldTemplate': 'CustomArrayFieldTemplate',
};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.fieldPathId: An object containing the id for this object & ids for its properties.items: An array of React nodes representing the items in the array.onAddClick: (event?) => void: A function that adds a new item to the end of 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.formData: The formData for this array.errorSchema: The optional validation errors for the array field and the items within it, in the form of anErrorSchemarawErrors: An array of strings listing all generated error messages from encountered errors for this widgetregistry: Theregistryobject.
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:FieldTemplateandui: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, fieldPathId } = props;
const id = descriptionId(fieldPathId);
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 field template to a uiSchema by specifying a ui:ArrayFieldDescriptionTemplate property with your Component :
import { UiSchema } from '@rjsf/utils';
import ArrayFieldDescriptionTemplate from './ArrayFieldDescriptionTemplate';
const uiSchema: UiSchema = {
'ui:ArrayFieldDescriptionTemplate': ArrayFieldDescriptionTemplate,
};or a string value from the Registry :
import { UiSchema } from '@rjsf/utils';
const uiSchema: UiSchema = {
'ui:ArrayFieldDescriptionTemplate': 'CustomArrayFieldDescriptionTemplate',
};The following props are passed to each ArrayFieldDescriptionTemplate:
description: The description of the array field being rendered.fieldPathId: The FieldPathId of the field in the hierarchyschema: The schema object for this array field.uiSchema: The uiSchema object for this array field.registry: Theregistryobject.
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 buttons rendered by ArrayFieldItemButtonsTemplate).
import { ArrayFieldItemTemplateProps, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
items: {
type: 'string',
},
};
function ArrayFieldItemTemplate(props: ArrayFieldItemTemplateProps) {
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.buttonsProps: The props to pass to theArrayFieldItemButtonTemplate.className: The className string.disabled: A boolean value stating if the array item is disabled.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 numberitemsin the array.itemKey: A stable, unique key for the array item.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: Theregistryobject.parentUiSchema: The UI schema of the array item's parent array field, used for customization in some themes
ArrayFieldItemButtonTemplate
The ArrayFieldItemButtonTemplate is used to render the representation of the buttons used for copying, moving and deleting an item in an array.
All of the ArrayFieldItemTemplate implementations in all themes get this template from the registry in order to render array fields items' buttons.
Currently, only the core them has an implementation of this template as the button rendering is identical across all themes.
If you want to change how an array field item's buttons are rendered you can customize this template (for instance to remove the move up/down and remove buttons).
import { useMemo } from 'react';
import { ArrayFieldTemplateItemButtonsType, buttonId, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
items: {
type: 'string',
},
};
function ArrayFieldItemButtonsTemplate(props: ArrayFieldTemplateItemButtonsType) {
const { disabled, readonly, hasCopy, fieldPathId, index, onCopyIndexClick, registry, uiSchema } = props;
const { CopyButton } = registry.templates.ButtonTemplates;
const onCopyClick = useMemo(() => onCopyIndexClick(index), [index, onCopyIndexClick]);
if (!hasCopy) {
return undefined;
}
return (
<CopyButton
id={buttonId(fieldPathId, 'copy')}
className='array-item-copy'
disabled={disabled || readonly}
onClick={onCopyClick}
uiSchema={uiSchema}
registry={registry}
/>
);
}
render(
<Form schema={schema} validator={validator} templates={{ ArrayFieldItemButtonsTemplate }} />,
document.getElementById('app'),
);The following props are passed to each ArrayFieldItemButtonsTemplate:
className: The className string.disabled: A boolean value stating if the array item is disabled.canAdd: A boolean value stating whether new elements 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.fieldPathId: The FieldPathId of the field in the hierarchy.index: A number stating the index the array item occurs initems.totalItems: A number stating the total numberitemsin the array.onAddItem: event?) => void: Callback function that adds a new item below this item.onCopyItem: (event?) => void: Callback function that copies this item below itself.onRemoveItem: (event?) => void: Callback function that removes the item from the list.onMoveUpItem: (event?) => void: Callback function that moves the item up one spot in the listonMoveDownItem: (event?) => void: Callback function that moves the item down one spot in the listreadonly: A boolean value stating if the array item is read-only.schema: The schema object for this array item.style: The optional style to pass to all of the buttonsuiSchema: The uiSchema object for this array item.registry: Theregistryobject.
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, fieldPathId } = props;
const id = titleId(fieldPathId);
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 with your Component :
import { UiSchema } from '@rjsf/utils';
import ArrayFieldDescriptionTemplate from './ArrayFieldDescriptionTemplate';
const uiSchema: UiSchema = {
'ui:ArrayFieldDescriptionTemplate': ArrayFieldDescriptionTemplate,
};or a string value from the Registry :
import { UiSchema } from '@rjsf/utils';
const uiSchema: UiSchema = {
'ui:ArrayFieldDescriptionTemplate': 'CustomArrayFieldDescriptionTemplate',
};The following props are passed to each ArrayFieldTitleTemplate:
title: The title of the array field being rendered.fieldPathId: The FieldPathId of the 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: Theregistryobject.
BaseInputTemplate
The BaseInputTemplate is the template to use to render the basic component for a theme. It is used as the template for rendering many of the 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 `` based widgets, you can customize this template.
For instance, say you have a CustomTextInput component that you want to integrate:
/* Detailed source-code truncated for AI context efficiency. */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: ABaseInputTemplateimplements a defaultonChangehandler that it passes to the HTML input component to handle theChangeEvent. Sometimes a widget may need to handle theChangeEventusing 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 withadditionalPropertiesandpatternProperties); 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.rawErrors: An array of strings listing all generated error messages from encountered errors for this widget.registry: Theregistryobject
CyclicSchemaExpandTemplate
The CyclicSchemaExpandTemplate is the template rendered by CyclicSchemaField when a circular $ref cycle is detected in the schema.
RJSF automatically detects when a $ref would recurse indefinitely (e.g. a schema whose property references its own root) and stops rendering at the cycle boundary.
At that point CyclicSchemaField renders this template, which shows a warning message and an expand button that the user can click to render one additional level of the recursive structure.
Each theme provides its own implementation.
You can replace the template globally via the templates prop on Form, or per-field via ui:CyclicSchemaExpandTemplate in the uiSchema.
import { CyclicSchemaExpandProps, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
// A schema that is self-referencing
const schema: RJSFSchema = {
$schema: 'http://json-schema.org/draft-07/schema#',
type: 'object',
title: 'Node',
properties: {
value: { type: 'string' },
child: { $ref: '#' },
},
};
function CyclicSchemaExpandTemplate<T = any>(props: CyclicSchemaExpandProps<T>) {
const { name, fieldPathId, onExpand } = props;
const buttonId = `${fieldPathId.$id}-button`;
return (
<div className='cyclic-expand'>
<span className='warning'>Circular reference detected for field "{name}"</span>
<button id={buttonId} type='button' onClick={() => onExpand(fieldPathId.$id)}>
Expand
</button>
</div>
);
}
render(
<Form schema={schema} validator={validator} templates={{ CyclicSchemaExpandTemplate }} />,
document.getElementById('app'),
);You can also provide a per-field template via uiSchema:
import { UiSchema } from '@rjsf/utils';
import CyclicSchemaExpandTemplate from './CyclicSchemaExpandTemplate';
const uiSchema: UiSchema = {
'ui:CyclicSchemaExpandTemplate': CyclicSchemaExpandTemplate,
};or a string value from the Registry:
import { UiSchema } from '@rjsf/utils';
const uiSchema: UiSchema = {
'ui:CyclicSchemaExpandTemplate': 'CustomCyclicSchemaExpandTemplate',
};The following props are passed to the CyclicSchemaExpandTemplate as defined by CyclicSchemaExpandProps in @rjsf/utils:
name: The unique name of the field at the cycle boundary, usually the property name within its parent object.fieldPathId: TheFieldPathIdof the field in the hierarchy; usefieldPathId.$idto get the HTML id string.onExpand: Callback to call when the user wants to render one additional level; receives the field's id string.schema: The schema object for the field at the cycle boundary.uiSchema: The uiSchema object for this field.registry: Theregistryobject.
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: Theregistryobject.
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 toFormuiSchema: The uiSchema that was passed toFormerrors: An array of all errors in thisForm.errorSchema: TheErrorSchemaconstructed byForm
FallbackFieldTemplate
The FallbackFieldTemplate is the template that renders opt-in fallback UI to control fields of unknown or unhandled types. Usage of this feature is controlled by the useFallbackUiForUnsupportedType Form prop.
import { FallbackFieldTemplateProps, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'unknownType',
title: 'My input',
};
function FallbackFieldTemplate(props: FallbackFieldTemplateProps) {
const { typeSelector, schemaField } = props;
return (
<div className={'row'}>
<div className={'col-xs-4'}>{typeSelector}</div>
<div className={'col-xs-8'}>{schemaField}</div>
</div>
);
}
render(
<Form schema={schema} validator={validator} templates={{ FallbackFieldTemplate }} />,
document.getElementById('app'),
);The following props are passed to the FallbackFieldTemplate:
schema: The schema for the fielduiSchema: The uiSchema for the fieldregistry: TheRegistryobject
1
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 fieldfieldPathId: The FieldPathId of the field in the hierarchyerrors: An array of all errors for this fielderrorSchema: TheErrorSchemafor this fieldregistry: TheRegistryobject
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, fieldPathId } = props;
const id = helpId(fieldPathId);
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 fieldfieldPathId: The FieldPathId of the field in the hierarchyhelp: The help information to be renderedregistry: TheRegistryobject
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 with your Component :
import { UiSchema } from '@rjsf/utils';
import CustomFieldTemplate from './CustomFieldTemplate';
const uiSchema: UiSchema = {
'ui:FieldTemplate': CustomFieldTemplate,
};or a string value from the Registry :
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 theStyleHTMLAttributesdefined 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 customDescriptionFieldTemplatedefined in thetemplatespassed to theForm).rawDescription: A string containing anyui:descriptionuiSchema 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:helpuiSchema directive defined.rawHelp: A string containing anyui:helpuiSchema directive defined. NOTE:rawHelpwill beundefinedif passedui:helpis 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.formData: The formData for this field.registry: Theregistryobject.
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".
GridTemplate
The GridTemplate is the template that renders a theme dependent Grid for either a row or column.
While it has only two explicit properties, it extends the GenericObjectTemplate in order to support passing any of the properties associated with a Grid implementation for any theme.
If you want to customize how grids are rendered you can.
import { Grid2 } from '@mui/material';
import { GridTemplateProps } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
import classNames from 'classnames';
const schema: RJSFSchema = {
type: 'string',
title: 'My input',
description: 'input description',
};
function GridTemplate(props: FieldHelpProps) {
const { children, column, className, ...rest } = props;
return (
<Grid2 item={column} {...rest} className={`${className} my-custom-grid-styling`}>
{children}
</Grid2>
);
}
render(<Form schema={schema} validator={validator} templates={{ GridTemplate }} />, document.getElementById('app'));The following props are passed to the GridTemplate:
children: The contents of the grid templatecolumn: Optional flag indicating whether the grid element represents a column, necessary for themes which have components for Rows vs Column
MultiSchemaFieldTemplate
Each theme implements a MultiSchemaFieldTemplate used to render the layout of a MultiSchemaField, i.e. a field described by a oneOf or anyOf schema.
The template typically renders a Widget used to select the schema to use, as well as a field for the selected schema.
import { MultiSchemaFieldTemplateProps, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
myField: {
oneOf: [
{
type: 'string',
title: 'String Field',
description: 'A field that accepts a string',
},
{
type: 'number',
title: 'Number Field',
description: 'A field that accepts a number',
},
],
},
},
};
function MultiSchemaFieldTemplate(props: MultiSchemaFieldTemplateProps) {
const { selector, optionSchemaField } = props;
return (
<div className='my-multi-schema-field-class'>
{selector}
<hr />
{optionSchemaField}
</div>
);
}
render(
<Form schema={schema} validator={validator} templates={{ MultiSchemaFieldTemplate }} />,
document.getElementById('app'),
);The following props are passed to the MultiSchemaFieldTemplate:
selector: The rendered Widget used to select a multischema option.optionSchemaField: The rendered SchemaField representing the selected option.schema: The schema object for the field.uiSchema: The uiSchema object for the field.registry: Theregistryobject.
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 with your Component :
import { UiSchema } from '@rjsf/utils';
import ObjectFieldTemplate from './ObjectFieldTemplate';
const uiSchema: UiSchema = {
'ui:ObjectFieldTemplate': ObjectFieldTemplate,
};or a string value from the Registry :
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.onAddProperty: () => void: Callback to use in order to add an new additionalProperty to the object field (to be used with additionalProperties and patternProperties)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.fieldPathId: The FieldPathId of the field in the hierarchyerrorSchema: The optional validation errors in the form of anErrorSchemaformData: The form data for the object.registry: Theregistryobject.
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:FieldTemplateandui:ObjectFieldTemplate.
OptionalDataControlsTemplate
Each theme implements a OptionalDataControlsTemplate used to render the Optional Data Controls when that feature has been enabled
/* Detailed source-code truncated for AI context efficiency. */The following props are passed to each OptionalDataControlsTemplate as defined by the OptionalDataControlsTemplateProps in @rjsf/utils:
id: The generated id for this Optional Data Control instance.label: The label to use for the Optional Data ControlonAddClick: Optional callback to call when clicking on the Optional Data Control to add dataonRemoveClick: Optional callback to call when clicking on the Optional Data Control to remove dataschema: The schema object for this object.uiSchema: The uiSchema object for this object field.registry: Theregistryobject.
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: Theregistryobject.
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.fieldPathId: The FieldPathId of the field in the hierarchyreason: The reason why the schema field has an unsupported type.registry: Theregistryobject.
WrapIfAdditionalTemplate
The WrapIfAdditionalTemplate is used by the FieldTemplate to conditionally render additional controls if additionalProperties or patternProperties are present in the schema.
You may customize WrapIfAdditionalTemplate if you wish to change the layout or behavior of user-controlled additionalProperties and patternProperties.
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,
onKeyRename,
onKeyRenameBlur,
onRemoveProperty,
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={onKeyRenameBlur} defaultValue={label} />
<div>{children}</div>
<RemoveButton onClick={onRemoveProperty} 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 theStyleHTMLAttributesdefined 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.onKeyRename: Callback used to handle the changing of an additional property key's name with the new valueonKeyRenameBlur: Callback used to handle the changing of an additional property key's name when the input is blurred. The event's target's value will be used as the new value. Its a wrapper callback aroundonKeyRenameonRemoveProperty: Callback used to handle the removal of the additionalProperty
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: Theregistryobject.
AddButton
The AddButton is used to render an add action on a Form for both a new additionalProperties or patternProperties 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 or patternProperties 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
submittypebuttonmay result in theFormnot submitting when pressed.
You could also choose to provide your own submit button as the children prop of theFormshould 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: Theregistryobject.
Custom Templates
You can now add custom components to the registry and reference them in your uiSchema using string keys.
Adding Custom Templates to the Registry
import CustomArrayFieldTemplate from './CustomArrayFieldTemplate';
import { UiSchema } from '@rjsf/utils';
// Add the custom template to the registry
const registry = { templates: { CustomArrayFieldTemplate } };
// Use the custom template in the uiSchema
const uiSchema: UiSchema = { 'ui:ArrayFieldTemplate': 'CustomArrayFieldTemplate' };Packages Docs Docs Advanced Customization Custom Themes (`packages/docs/docs/advanced-customization/custom-themes.md`)
Custom Themes
The withTheme component provides an easy way to extend the functionality of react-jsonschema-form by passing in a theme object that defines custom/overridden widgets and fields, as well as any of the other possible properties of the standard rjsf Form component.
This theme-defining object is passed as the only parameter to the HOC (withTheme(ThemeObj)), and the HOC will return a themed-component which you use instead of the standard Form component.
Usage
import React, { Component } from 'react';
import validator from '@rjsf/validator-ajv8';
import { withTheme, ThemeProps } from '@rjsf/core';
const theme: ThemeProps = { widgets: { test: () => <div>test</div> } };
const ThemedForm = withTheme(theme);
const Demo = () => <ThemedForm schema={schema} uiSchema={uiSchema} validator={validator} />;Theme object properties
The Theme object consists of the same properties as the rjsf Form component (such as widgets, fields and templates).
The themed-Form component merges together any theme-specific widgets, fields and templates with the default widgets, fields and templates.
For instance, providing a single widget in widgets will merge this widget with all the default widgets of the rjsf Form component, but overrides the default if the theme's widget's name matches the default widget's name.
Thus, for each default widget or field not specified/overridden, the themed-form will rely on the defaults from the rjsf Form.
Note that you are not required to pass in either custom widgets, fields or templates when using the custom-themed HOC component;
you can essentially redefine the default Form by simply doing const Form = withTheme({});.
Widgets and fields
widgets and fields should be in the same format as shown here.
Example theme with custom widget:
import { WidgetProps, RegistryWidgetsType } from '@rjsf/utils';
import { ThemeProps } from '@rjsf/core';
const MyCustomWidget = (props: WidgetProps) => {
return (
<input
type='text'
className='custom'
value={props.value}
required={props.required}
onChange={(event) => props.onChange(event.target.value)}
/>
);
};
const myWidgets: RegistryWidgetsType = {
myCustomWidget: MyCustomWidget,
};
const ThemeObject: ThemeProps = { widgets: myWidgets };
export default ThemeObject;The above can be similarly done for fields and templates.
Templates
Each template should be passed into the theme object via the templates object just as you would into the rjsf Form component. Here is an example of how to use a custom ArrayFieldTemplate and ErrorListTemplate in the theme object:
import { ArrayFieldTemplateProps, ErrorListProps } from '@rjsf/utils';
import { ThemeProps } from '@rjsf/core';
function MyArrayFieldTemplate(props: ArrayFieldTemplateProps) {
return (
<div>
{props.items.map((element) => element.children)}
{props.canAdd && <button type='button' onClick={props.onAddClick}></button>}
</div>
);
}
function MyErrorListTemplate(props: ErrorListProps) {
const { errors } = props;
return (
<ul>
{errors.map((error) => (
<li key={error.stack}>{error.stack}</li>
))}
</ul>
);
}
const ThemeObject: ThemeProps = {
templates: {
ArrayFieldTemplate: MyArrayFieldTemplate,
ErrorListTemplate: MyErrorListTemplate,
},
widgets: myWidgets,
};
export default ThemeObject;Overriding other Form props
Just as the theme can override widgets, fields, any of the templates, and set default values to properties like showErrorList, you can do the same with the instance of the withTheme() Form component.
import { ThemeProps } from '@rjsf/core';
const ThemeObject: ThemeProps = {
templates: {
ArrayFieldTemplate: MyArrayFieldTemplate,
},
fields: myFields,
showErrorList: false,
widgets: myWidgets,
};Thus, the user has higher priority than the withTheme HOC, and the theme has higher priority than the default values of the rjsf Form component (User > Theme > Defaults).
Packages Docs Docs Advanced Customization Custom Widgets Fields (`packages/docs/docs/advanced-customization/custom-widgets-fields.md`)
Custom Widgets and Fields
The API allows to specify your own custom widget and field components:
- A widget represents a HTML tag for the user to enter data, eg.
input,select, etc. - A field usually wraps one or more widgets and most often handles internal field state; think of a field as a form row, including the labels.
Customizing the default fields and widgets
You can override any default field and widget, including the internal widgets like the CheckboxWidget that BooleanField
renders for boolean values. You can override any field and widget just by providing the customized fields/widgets in thefields and widgets props:
import { RJSFSchema, UiSchema, WidgetProps, RegistryWidgetsType } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'boolean',
default: true,
};
const uiSchema: UiSchema = {
'ui:widget': 'checkbox',
};
const CustomCheckbox = function (props: WidgetProps) {
return (
<button id='custom' className={props.value ? 'checked' : 'unchecked'} onClick={() => props.onChange(!props.value)}>
{String(props.value)}
</button>
);
};
const widgets: RegistryWidgetsType = {
CheckboxWidget: CustomCheckbox,
};
render(
<Form schema={schema} uiSchema={uiSchema} validator={validator} widgets={widgets} />,
document.getElementById('app'),
);This allows you to create a reusable customized form class with your custom fields and widgets:
import { RegistryFieldsType, RegistryWidgetsType } from '@rjsf/utils';
import { FormProps } from '@rjsf/core';
const customFields: RegistryFieldsType = { StringField: CustomString };
const customWidgets: RegistryWidgetsType = { CheckboxWidget: CustomCheckbox };
function MyForm(props: FormProps) {
return <Form fields={customFields} widgets={customWidgets} {...props} />;
}The default fields you can override are:
ArrayFieldArraySchemaFieldBooleanFieldDescriptionFieldOneOfFieldAnyOfFieldLayoutGridFieldLayoutMultiSchemaFieldLayoutHeaderFieldNullFieldNumberFieldObjectFieldSchemaFieldStringFieldTitleFieldUnsupportedFieldFallbackFieldCyclicSchemaField
The default widgets you can override are:
AltDateTimeWidgetAltDateWidgetCheckboxesWidgetCheckboxWidgetColorWidgetDateTimeWidgetDateWidgetEmailWidgetFileWidgetHiddenWidgetPasswordWidgetRadioWidgetRangeWidgetSelectWidgetTextareaWidgetTextWidgetTimeWidgetUpDownWidgetURLWidget
Raising errors from within a custom widget or field
You can raise custom 'live validation' errors by overriding the onChange method to provide feedback while users are actively changing the form data.
If you do set errors this way, you must also clear them this way by passing undefined to the onChange() for the errorSchema parameter.
:::warning
While these errors are retained during validation, it is still preferred for you to use the customValidate Form prop mechanism instead.
:::
import { ErrorSchema, RJSFSchema, UiSchema, WidgetProps, RegistryWidgetsType } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'text',
default: 'hello',
};
const uiSchema: UiSchema = {
'ui:widget': 'text',
};
const CustomTextWidget = function (props: WidgetProps) {
const { id, value } = props;
const raiseErrorOnChange = ({ target: { value } }: ChangeEvent<HTMLInputElement>) => {
let raiseError: ErrorSchema | undefined;
if (value !== 'test') {
raiseError = {
__errors: ['Value must be "test"'],
};
}
props.onChange(value, [], raiseError, id);
};
return <input id={id} onChange={raiseErrorOnChange} value={value || ''} />;
};
const widgets: RegistryWidgetsType = {
TextWidget: CustomTextWidget,
};
render(
<Form schema={schema} uiSchema={uiSchema} validator={validator} widgets={widgets} />,
document.getElementById('app'),
);This creates a custom text widget that raises an error if the input value does not match 'test'.
Adding your own custom widgets
You can provide your own custom widgets to a uiSchema for the following json data types:
stringnumberintegerbooleanarray
import { RJSFSchema, UiSchema, WidgetProps } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: Schema = {
type: 'string',
};
const uiSchema: UiSchema = {
'ui:widget': (props: WidgetProps) => {
return (
<input
type='text'
className='custom'
value={props.value}
required={props.required}
onChange={(event) => props.onChange(event.target.value)}
/>
);
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));The following props are passed to custom widget components:
id: The generated id for this widget, used to provide uniquenames andids for the HTML field elements rendered by widgets;name: The unique name of the field, usually derived from the name of the property in the JSONSchema; Provided in support of custom widgets;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;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 stringhideLabel: A boolean value, if true, will cause the label to be hidden. This is useful for nested fields where you don't want to clutter the UI. Customized vialabelin theUiSchema;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;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.rawErrors: An array of strings listing all generated error messages from encountered errors for this widget.registry: A registry object (read next).
Custom component registration
Alternatively, you can register them all at once by passing the widgets prop to the Form component, and reference their identifier from the uiSchema:
import { RJSFSchema, UiSchema, WidgetProps, RegistryWidgetsType } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const MyCustomWidget = (props: WidgetProps) => {
return (
<input
type='text'
className='custom'
value={props.value}
required={props.required}
onChange={(event) => props.onChange(event.target.value)}
/>
);
};
const widgets: RegistryWidgetsType = {
myCustomWidget: MyCustomWidget,
};
const schema: RJSFSchema = {
type: 'string',
};
const uiSchema: UiSchema = {
'ui:widget': 'myCustomWidget',
};
render(
<Form schema={schema} uiSchema={uiSchema} validator={validator} widgets={widgets} />,
document.getElementById('app'),
);This is useful if you expose the uiSchema as pure JSON, which can't carry functions.
Custom widget options
If you need to pass options to your custom widget, you can add a ui:options object containing those properties. If the widget has defaultProps, the options will be merged with the (optional) options object from defaultProps:
import { RJSFSchema, UiSchema, WidgetProps } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'string',
};
function MyCustomWidget(props: WidgetProps) {
const { options } = props;
const { color, backgroundColor } = options;
return <input style={{ color, backgroundColor }} />;
}
MyCustomWidget.defaultProps = {
options: {
color: 'red',
},
};
const uiSchema: UiSchema = {
'ui:widget': MyCustomWidget,
'ui:options': {
backgroundColor: 'yellow',
},
};
// renders red on yellow input
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));Note: This also applies to registered custom components.
Customizing widgets' text input
All the widgets that render a text input use the BaseInputTemplate component internally. If you need to customize all text inputs without customizing all widgets individually, you can provide a BaseInputTemplate component in the templates property of Form (see Custom Templates).
Wrapping an existing widget to customize it
Sometimes you just need to customize the properties that are passed to an existing widget.
The way to do this varies based upon whether you are using core or some other theme (such as mui).
Here is an example of modifying the SelectWidget to change the ordering of enumOptions:
import { WidgetProps } from '@rjsf/utils';
import { getDefaultRegistry } from '@rjsf/core';
import { Widgets } from '@rjsf/mui';
import myOptionsOrderFunction from './myOptionsOrderFunction';
const {
widgets: { SelectWidget },
} = getDefaultRegistry(); // To get widgets from core
// const { SelectWidget } = Widgets; // To get widgets from a theme do this
function MySelectWidget(props: WidgetProps) {
const { options } = props;
let { enumOptions } = options;
// Reorder the `enumOptions` however you want
enumOptions = myOptionsOrderFunction(enumOptions);
return <SelectWidget {...props} options={{ ...options, enumOptions }} />;
}Custom field components
You can provide your own field components to a uiSchema for basically any json schema data type, by specifying a ui:field property.
For example, let's create and register a dumb geo component handling a latitude and a longitude:
import { RJSFSchema, UiSchema, FieldProps, RegistryFieldsType } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
required: ['lat', 'lon'],
properties: {
lat: { type: 'number' },
lon: { type: 'number' },
},
};
// Define a custom component for handling the root position object
class GeoPosition extends React.Component<FieldProps> {
constructor(props: FieldProps) {
super(props);
this.state = { ...props.formData };
}
onChange(name) {
return (event) => {
this.setState(
{
[name]: parseFloat(event.target.value),
},
() => this.props.onChange(this.state),
);
};
}
render() {
const { lat, lon } = this.state;
return (
<div>
<input type='number' value={lat} onChange={this.onChange('lat')} />
<input type='number' value={lon} onChange={this.onChange('lon')} />
</div>
);
}
}
// Define the custom field component to use for the root object
const uiSchema: UiSchema = { 'ui:field': 'geo' };
// Define the custom field components to register; here our "geo"
// custom field component
const fields: RegistryFieldsType = { geo: GeoPosition };
// Render the form with all the properties we just defined passed
// as props
render(
<Form schema={schema} uiSchema={uiSchema} validator={validator} fields={fields} />,
document.getElementById('app'),
);Note: Registered fields can be reused across the entire schema.
Field props
A field component will always be passed the following props:
schema: The JSON subschema object for this field;uiSchema: The uiSchema for this field;idSchema: The FieldPathId of the field in the hierarchyformData: The data for this field;errorSchema: The tree of errors for this field and its children;registry: A registry object (read next).required: The required status of this field;disabled: A boolean value stating if the field is disabled;readonly: A boolean value stating if the field is read-only;autofocus: A boolean value stating if the field should autofocus;name: The unique name of the field, usually derived from the name of the property in the JSONSchemarawErrors: `An array of strings listing all generated error messages from encountered errors for this fieldonChange: 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 changedonBlur: The input blur event handler; call it with the field id and value;onFocus: The input focus event handler; call it with the field id and value;
The `registry` object
The registry is an object containing the registered core, theme and custom fields and widgets as well as the root schema, form context, schema utils.
fields: The set of all fields used by theForm. Includes fields fromcore, theme-specific fields and any custom registered fields;widgets: The set of all widgets used by theForm. Includes widgets fromcore, theme-specific widgets and any custom registered widgets, if any;templates: The set of templates used by theForm. Includes templates fromcore, theme-specific templates and any custom registered templatesrootSchema: The root schema, as passed to theForm, which can contain referenced definitions;schemaUtils: The current implementation of theSchemaUtilsType(from@rjsf/utils) in use by theForm. Used to call any of the validation-schema-based utility functions.translateString: The string translation function to use when displaying any of the RJSF strings in templates, fields or widgetsglobalFormOptions: The global Form Options that are available for all templates, fields and widgets to accessglobalUiOptions: The optional global UI Options that are available for all templates, fields and widgets to access
The registry is passed down the component tree, so you can access it from your custom field, custom widget, custom template and SchemaField components.
Custom SchemaField
Warning: This is a powerful feature as you can override the whole form behavior and easily mess it up. Handle with care.
You can provide your own implementation of the SchemaField base React component for rendering any JSONSchema field type, including objects and arrays. This is useful when you want to augment a given field type with supplementary powers.
To proceed so, pass a fields object having a SchemaField property to your Form component; here's an example:
import { RJSFSchema, FieldProps, RegistryFieldsType } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const CustomSchemaField = function (props: FieldProps) {
return (
<div id='custom'>
<p>Yeah, I'm pretty dumb.</p>
<div>My props are: {JSON.stringify(props)}</div>
</div>
);
};
const fields: RegistryFieldsType = {
SchemaField: CustomSchemaField,
};
const schema: RJSFSchema = {
type: 'string',
};
render(<Form schema={schema} validator={validator} fields={fields} />, document.getElementById('app'));If you're curious how this could ever be useful, have a look at the Kinto formbuilder repository to see how it's used to provide editing capabilities to any form field.
Props passed to a custom SchemaField are the same as the ones passed to a custom field.
Custom ArraySchemaField
Everything that was mentioned above for a Custom SchemaField applies, but this is only used to render the Array item children that are then passed to the ArrayFieldItemTemplate.
By default, ArraySchemaField is not actually implemented in the fields list since ArrayField falls back to SchemaField if ArraySchemaField is not provided.
If you want to customize how the individual items for an array are rendered, provide your implementation of ArraySchemaField as a fields override.
import { RJSFSchema, UiSchema, FieldProps, RegistryFieldsType } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const CustomArraySchemaField = function (props: FieldProps) {
const { index, registry } = props;
const { SchemaField } = registry.fields;
const name = `Index ${index}`;
return <SchemaField {...props} name={name} />;
};
const fields: RegistryFieldsType = {
ArraySchemaField: CustomArraySchemaField,
};
const schema: RJSFSchema = {
type: 'string',
};
render(<Form schema={schema} validator={validator} fields={fields} />, document.getElementById('app'));Custom Field by Id
Warning: This is a powerful feature as you can override the whole form behavior and easily mess it up. Handle with care.
You can provide your own implementation of the field component that applies to any schema or sub-schema based on the schema's $id value. This is useful when your custom field should be conditionally applied based on the schema rather than the property name or data type.
To provide a custom field in this way, the fields prop should be an object which contains a key that matches the $id value of the schema which should have a custom field; here's an example:
import { RJSFSchema, FieldProps, RegistryFieldsType } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const CustomIdField = function (props: FieldProps) {
return (
<div id='custom'>
<p>Yeah, I'm pretty dumb.</p>
<div>My props are: {JSON.stringify(props)}</div>
</div>
);
};
const fields: RegistryFieldsType = {
'/schemas/my-id': CustomIdField,
};
const schema: RJSFSchema = {
$id: '/schemas/my-id',
type: 'string',
};
render(<Form schema={schema} validator={validator} fields={fields} />, document.getElementById('app'));Wrapping an existing field to customize it
Sometimes you just need to customize the properties that are passed to an existing field.
Here is an example of wrapping the ObjectField to tweak the onChange handler to look for a specific kind of bad data:
import { useCallback } from 'react';
import { FieldProps } from '@rjsf/utils';
import { getDefaultRegistry } from '@rjsf/core';
import checkBadData from './checkBadData';
const {
fields: { ObjectField },
} = getDefaultRegistry();
function MyObjectField(props: FieldProps) {
const { onChange } = props;
const onChangeHandler = useCallback(
(newFormData: T | undefined, path: (number | string)[], es?: ErrorSchema<T>, id?: string) => {
let data = newFormData;
let error = es;
if (checkBadData(newFormData)) {
// Format the `error` and fix the `data` here
}
onChange(data, path, error, id);
},
[onChange],
);
return <ObjectField {...props} onChange={onChangeHandler} />;
}Packages Docs Docs Advanced Customization Internals (`packages/docs/docs/advanced-customization/internals.md`)
Internals
Miscellaneous internals of react-jsonschema-form are listed here.
JSON Schema supporting status
This component follows JSON Schema specs. We currently support JSON Schema-07 by default, but we also support other JSON schema versions through the custom schema validation feature. Due to the limitation of form widgets, there are some exceptions as follows:
additionalItemskeyword for arraysThis keyword works when
itemsis an array.additionalItems: trueis not supported because there's no widget to represent an item of any type. In this case it will be treated as no additional items allowed.additionalItemsbeing a valid schema is supported.anyOf,allOf, andoneOf, or multipletypes(i.e."type": ["string", "array"])The
anyOfandoneOfkeywords are supported; however, properties declared inside theanyOf/oneOfshould not overlap with properties "outside" of theanyOf/oneOf.You can also use
oneOfwith schema dependencies to dynamically add schema properties based on input data.The
allOfkeyword is supported; it uses @x0k/json-schema-merge to merge subschemas to render the final combined schema in the form. When these subschemas are incompatible, though (or if the library has an error merging it), theallOfkeyword is dropped from the schema."additionalProperties":falseproduces incorrect schemas when used with schema dependencies. This library does not remove extra properties, which causes validation to fail. It is recommended to avoid setting"additionalProperties":falsewhen you use schema dependencies. See #848 #902 #992
Handling of schema defaults
This library automatically fills default values defined in the JSON Schema as initial values in your form. This also works for complex structures in the schema. If a field has a default defined, it should always appear as default value in form. This also works when using schema dependencies.
Since there is a complex interaction between any supplied original form data and any injected defaults, this library tries to do the injection in a way which keeps the original intention of the original form data.
Check out the defaults example on the live playground to see this in action.
Merging of defaults into the form data
There are three different cases which need to be considered for the merging. Objects, arrays and scalar values. This library always deeply merges any defaults with the existing form data for objects.
This are the rules which are used when injecting the defaults:
- When there is a scalar in the form data, nothing is changed.
- When the value is
undefinedin the form data, the default is created in the form data. - When the value is an object in the form data, the defaults are deeply merged into the form data, using the rules defined here for the deep merge.
- Then the value is an array in the form data, defaults are only injected in existing array items. No new array items will be created, even if the schema has minItems or additional items defined.
A boolean property that is listed in its parent's required array and has no default of its own is populated with false. You can turn this off using the experimental requiredBooleanDefault flag, so that the property stays undefined until the user answers it.
Merging of defaults within the schema
In the schema itself, defaults of parent elements are propagated into children. So when you have a schema which defines a deeply nested object as default, these defaults will be applied to children of the current node. This also merges objects defined at different levels together, with the deeper (descendant) default taking precedence for any overlapping properties by default. You can change this behavior using the experimental nestedDefaultsPrecedence flag. If the parent node defines properties which are not defined in the child, they will be merged so that the default for the child will be the merged defaults of parent and child.
For arrays this is not the case. Defining an array, when a parent also defines an array, will be overwritten. This is only true when arrays are used in the same level, for objects within these arrays, they will be deeply merged again.
Custom array field buttons
The ArrayField component provides a UI to add, copy, remove and reorder array items, and these buttons use Bootstrap glyphicons.
If you don't use glyphicons but still want to provide your own icons or texts for these buttons, you can easily do so using CSS:
NOTE this only applies to the
@rjsf/coretheme
i.glyphicon {
display: none;
}
.btn-add::after {
content: 'Add';
}
.array-item-copy::after {
content: 'Copy';
}
.array-item-move-up::after {
content: 'Move Up';
}
.array-item-move-down::after {
content: 'Move Down';
}
.array-item-remove::after {
content: 'Remove';
}Submit form programmatically
You can use the reference to get your Form component and call the submit method to submit the form programmatically without a submit button.
This method will dispatch the submit event of the form, and the function, that is passed to onSubmit props, will be called.
import { createRef } from 'react';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import { Form } from '@rjsf/core';
import validator from '@rjsf/validator-ajv8';
const onSubmit = ({ formData }) => console.log('Data submitted: ', formData);
let yourForm;
const schema: RJSFSchema = {
type: 'string',
};
const formRef = createRef<Form>();
render(
<Form schema={schema} validator={validator} onSubmit={onSubmit} ref={formRef} />,
document.getElementById('app'),
);
formRef.current.submit();Update field value in form programmatically
You can use the reference to get your Form component and call the setFieldValue(fieldPath: string | FieldPathList, newValue?: T): void method to change the value of a field.
This method will dispatch the onChange event of the form.
import { createRef } from 'react';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import { Form } from '@rjsf/core';
import validator from '@rjsf/validator-ajv8';
const onChange = ({ formData }) => console.log('Data updated to: ', formData);
let yourForm;
const schema: RJSFSchema = {
type: 'object',
properties: {
foo: {
type: 'object',
required: ['input'],
properties: {
input: {
type: 'string',
},
},
},
},
required: ['foo'],
};
const formRef = createRef<Form>();
render(
<Form schema={schema} validator={validator} onSubmit={onSubmit} ref={formRef} />,
document.getElementById('app'),
);
formRef.current.setFieldValue('foo.input', 'value');
formRef.current.setFieldValue(['foo'], { input: 'newvalue' });
formRef.current.setFieldValue('', { foo: { input: 'another value' } });
formRef.current.setFieldValue([], { foo: { input: 'more values' } });Packages Docs Docs Advanced Customization Typescript (`packages/docs/docs/advanced-customization/typescript.md`)
Typescript Support
RJSF fully supports Typescript.
The types and functions exported by @rjsf/utils are fully typed (as needed) using one or more of the following 3 optional generics:
T = any: This represents the type of theformDataand defaults toany.S extends StrictRJSFSchema = RJSFSchema: This represents the type of theschemaand extends theStrictRJSFSchematype and defaults to theRJSFSchematype.F extends FormContextType = any: This represents the type of theformContext, extends theFormContextTypetype and defaults toany.
Every other library in the @rjsf/* ecosystem use these same generics in their functions and React component definitions.
For instance, in the @rjsf/core library the definitions of the Form component and the withTheme() and getDefaultRegistry() functions are as follows:
export default class Form<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
> extends Component<FormProps<T, S, F>, FormState<T, S, F>> {
// ... class implementation
}
export default function withTheme<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(
themeProps: ThemeProps<T, S, F>
) {
// ... function implementation
}
export default function getDefaultRegistry<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
>(): Omit<Registry<T, S, F>, 'schemaUtils'> {
// ... function implementation
}Out of the box, the defaults for these generics will work for all use-cases.
Providing custom types for any of these generics may be useful for situations where the caller is working with typed formData, schema or formContext props, Typescript is complaining and type casting isn't allowed.
Overriding generics
T
The generic T is used to represent the type of the formData property passed into Form.
If you are working with a simple, unchanging JSON Schema and you have defined a type for the formData you are working with, you can override this generic as follows:
import { RJSFSchema } from '@rjsf/utils';
import { customizeValidator } from '@rjsf/validator-ajv8';
import { Form } from '@rjsf/core';
interface FormData {
foo?: string;
bar?: number;
}
const schema: RJSFSchema = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' },
},
};
const formData: FormData = {};
const validator = customizeValidator<FormData>();
render(<Form<FormData> schema={schema} validator={validator} formData={formData} />, document.getElementById('app'));S
The generic S is used to represent the type of the schema property passed into Form.
If you are using something like the Ajv utility types for schemas typing system, you can override this generic as follows:
import { JSONSchemaType } from 'ajv';
import { RJSFSchema } from '@rjsf/utils';
import { customizeValidator } from '@rjsf/validator-ajv8';
import { Form } from '@rjsf/core';
interface FormData {
foo?: string;
bar?: number;
}
type MySchema = JSONSchemaType<FormData>;
const schema: MySchema = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' },
},
};
const validator = customizeValidator<any, MySchema>();
render(<Form<any, MySchema> schema={schema} validator={validator} />, document.getElementById('app'));
// Alternatively since you have the type, you could also use this
// const validator = customizeValidator<FormData, MySchema>();
// render((
// <Form<FormData, MySchema> schema={schema} validator={validator} />
//), document.getElementById("app"));NOTE: using this
Ajv typing systemhas not been tested extensively with RJSF, so use carefully
F
The generic F is used to represent the type of the formContext property passed into Form.
If you have a type for this data, you can override this generic as follows:
import { RJSFSchema } from '@rjsf/utils';
import { customizeValidator } from '@rjsf/validator-ajv8';
import { Form } from '@rjsf/core';
interface FormContext {
myCustomWidgetData: object;
}
const schema: RJSFSchema = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' },
},
};
const formContext: FormContext = {
myCustomWidgetData: {
enableCustomFeature: true,
},
};
const validator = customizeValidator<any, RJSFSchema, FormContext>();
render(
<Form<any, RJSFSchema, FormContext> schema={schema} validator={validator} formContext={formContext} />,
document.getElementById('app')
);Overriding generics in core
As shown in previous examples, overriding the default Form from @rjsf/core is pretty straight forward.
Using the withTheme() function is just as easy:
import { RJSFSchema } from '@rjsf/utils';
import { customizeValidator } from '@rjsf/validator-ajv8';
import { withTheme, ThemeProps } from '@rjsf/core';
interface FormData {
foo?: string;
bar?: number;
}
type MySchema = JSONSchemaType<FormData>;
const schema: MySchema = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' },
},
};
interface FormContext {
myCustomWidgetData: object;
}
const theme: ThemeProps<FormData, MySchema, FormContext> = {
widgets: { test: () => <div>test</div> },
};
const ThemedForm = withTheme<FormData, MySchema, FormContext>(theme);
const validator = customizeValidator<FormData, MySchema, FormContext>();
const Demo = () => <ThemedForm schema={schema} uiSchema={uiSchema} validator={validator} />;Overriding generics in other themes
Since all the other themes in RJSF are extensions of @rjsf/core, overriding parts of these themes with custom generics is a little different.
The exported Theme and Form from any of the themes have been created using the generic defaults, and as a result, do not take generics themselves.
In order to override generics, special generateForm() and generateTheme() functions are exported for your use.
Overriding a Theme
If you are doing something like the following to create a new theme based on @rjsf/mui to extend one or more templates:
import React from 'react';
import { WidgetProps } from '@rjsf/utils';
import { ThemeProps, withTheme } from '@rjsf/core';
import validator from '@rjsf/validator-ajv8';
import { Theme } from '@rjsf/mui';
const OldBaseInputTemplate = Theme.templates.BaseInputTemplate;
// Force the underlying `TextField` component to always use size="small"
function MyBaseInputTemplate(props: WidgetProps) {
return <OldBaseInputTemplate {...props} size='small' />;
}
const myTheme: ThemeProps = {
...Theme,
templates: {
...Theme.templates,
BaseInputTemplate: MyBaseInputTemplate,
},
};
const ThemedForm = withTheme(myTheme);
const Demo = () => <ThemedForm schema={schema} uiSchema={uiSchema} validator={validator} />;Then you would use the new generateTheme() and generateForm() functions as follows:
import React from 'react';
import { WidgetProps } from '@rjsf/utils';
import { ThemeProps, withTheme } from '@rjsf/core';
import { customizeValidator } from '@rjsf/validator-ajv8';
import { generateTheme } from '@rjsf/mui';
interface FormData {
foo?: string;
bar?: number;
}
type MySchema = JSONSchemaType<FormData>;
const schema: MySchema = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'number' },
},
};
interface FormContext {
myCustomWidgetData: object;
}
const Theme: ThemeProps<FormData, MySchema, FormContext> = generateTheme<FormData, MySchema, FormContext>();
const OldBaseInputTemplate = Theme.templates.BaseInputTemplate;
// Force the underlying `TextField` component to always use size="small"
function MyBaseInputTemplate(props: WidgetProps<FormData, MySchema, FormContext>) {
return <OldBaseInputTemplate {...props} size='small' />;
}
const myTheme: ThemeProps<FormData, MySchema, FormContext> = {
...Theme,
templates: {
...Theme.templates,
BaseInputTemplate: MyBaseInputTemplate,
},
};
const ThemedForm = withTheme<FormData, MySchema, FormContext>(myTheme);
const validator = customizeValidator<FormData, MySchema, FormContext>();
// You could also do since they are effectively the same:
// const ThemedForm = generateForm<FormData, MySchema, FormContext>(myTheme);
const Demo = () => <ThemedForm schema={schema} uiSchema={uiSchema} validator={validator} />;NOTE: The same approach works for extending
widgetsandfieldsas well.
Packages Docs Docs Api Reference LayoutGridField (`packages/docs/docs/api-reference/LayoutGridField.md`)
LayoutGridField
The LayoutGridField will render a schema, uiSchema and formData combination out into a GridTemplate in the shape
described in the uiSchema. To define the grid to use to render the elements within a field in the schema, provide in
the uiSchema for that field the object contained under a ui:layoutGrid element. E.g. (as a JSON object):
{
"field1" : {
"ui:field": "LayoutGridField",
"ui:layoutGrid": {
"ui:row": { ... }
}
}
}See the LayoutGridField usage for more detailed walk-through on how to use the component. This page is condensed
version of the uiSchema APIs for faster reference.
`ui:row`
The outermost level of a LayoutGridField is the ui:row that defines the nested rows, columns, and/or condition
elements (i.e. "grid elements") in the grid. This definition is either a simple "grid elements" OR an object with
native GridTemplate implementation-specific props and a children array of "grid elements". E.g. (as JSON objects):
Simple ui:row definition, without additional GridTemplate props:
{
"ui:row": [
{ "ui:row"|"ui:col"|"ui:columns"|"ui:condition": ... },
...
]
}Complex ui:row definition, with additional GridTemplate (this example uses @mui/material/Grid2 native props):
{
"ui:row": {
"spacing": 2,
"size": {
"md": 4
},
"alignContent": "flex-start",
"className": "GridRow",
"children": [
{
"ui:row"|"ui:col"|"ui:columns"|"ui:condition": ...
},
...
]
}
}NOTE: Special note about the native
classNameprop values. All className values will automatically be looked up in
theformContext.lookupMapin case they have been defined using a CSS-in-JS approach. In other words, from the
example above, if theFormwas constructed with alayoutGridLookupMapset to{ GridRow: cssInJs.GridRowClass }
then when rendered, the nativeGridTemplatewill get theclassNamewith the value fromcssInJs.GridRowClass. This automatic lookup will happen for any of the "grid elements" when rendering withGridTemplateprops. If multiple className values are present, for example:{ className: 'GridRow GridColumn' }, the classNames are split apart, looked up individually, and joined
together to form one className with the values fromcssInJs.GridRowClassandcssInJs.GridColumnClass. See the
example in the usage documentation.
`ui:col`
The ui:col grid element is used to specify the list of columns within a grid row. A ui:col element can take on
several forms:
- a simple list of dotted-path field names within the root field;
- a list of objects containing the dotted-path field
nameany other props that are gathered intoui:optionsfor the field; - a list with a one-off
renderfunctional component with or without a non-fieldnameidentifier and any other to-be-spread props; and - an object with native
GridTemplateimplementation specific props and achildrenarray with 1) or 2) or even a nestedui:rowor aui:conditioncontaining aui:row(although this should be used carefully). E.g. (as JSON objects):
Simple ui:col definition, without additional GridTemplate props and form 1 only children:
{
"ui:col": ["innerField", "inner.grandChild", ...]
}Complicated ui:col definition, without additional GridTemplate props and form 2 only children:
{
"ui:col": [
{ "name": "innerField", "fullWidth": true },
{ "name": "inner.grandChild", "fullWidth": false },
...
]
}More complicated ui:col definition, without additional GridTemplate props and form 2 children, one being a
one-off render functional component without a non-field name identifier
{
"ui:col": [
"innerField",
{
"render": "WizardNavButton",
"isNext": true,
"size": "large"
}
]
}Most complicated ui:col definition, additional GridTemplate props and form 1, 2 and 3 children (this example
uses @mui/material/Grid2 native props):
{
"ui:col": {
"size": { "md": 4 },
"className": "GridColumn",
"children": [
"innerField",
{ "name": "inner.grandChild", "fullWidth": true },
{ "name": "customRender", "render": "CustomRender", "toSpread": "prop-value" },
{ "ui:row|ui:condition": ... },
...
]
}
}NOTE: If a
nameprop does not exist or its value does not match any field in a schema, then it is assumed to be a
customrendercomponent. If therenderprop does not exist, a null render will occur. Ifrenderis a
string, its value will be looked up in theformContext.lookupMapfirst before defaulting to a null render. If the
resulting looked uprenderis not a function (React components are functions), then it will be a null render.
`ui:columns`
The ui:columns grid element is syntactic sugar to specify a set of ui:col columns that all share the same set of
native GridTemplate props. In other words rather than writing the following configuration that renders a<GridTemplate> element with 3 <GridTemplate column className="GridColumn col-md-4"> nodes and 2<GridTemplate column className="col-md-6"> nodes within it (one for each of the fields contained in the children
list):
{
"ui:row": {
"children": [
{
"ui:col": {
"className": "GridColumn col-md-4",
"children": ["innerField"]
}
},
{
"ui:col": {
"className": "GridColumn col-md-4",
"children": ["inner.grandChild"]
}
},
{
"ui:col": {
"className": "GridColumn col-md-4",
"children": [{ "name": "inner.grandChild2" }]
}
},
{
"ui:col": {
"className": "col-md-6",
"children": ["innerField2"]
}
},
{
"ui:col": {
"className": "col-md-6",
"children": ["inner.grandChild3"]
}
}
]
}
}One can write this instead:
{
"ui:row": {
"children": [
{
"ui:columns": {
"className": "GridColumn col-md-4",
"children": ["innerField", "inner.grandChild", { "name": "inner.grandChild2", "fullWidth": true }]
}
},
{
"ui:columns": {
"className": "col-md-6",
"children": ["innerField2", "inner.grandChild3"]
}
}
]
}
}NOTE: This syntax differs from
"ui:col": { "className": "col-md-6", "children": ["innerField2", "inner.grandChild3"] }in that
theui:colwill render the two children fields inside a single<GridTemplate "className": "col-md-6",>
element.
`ui:condition`
The final grid element, ui:condition, allows for conditionally displaying "grid elements" within a row based on the
current value of a field as it relates to a (list of) hard-coded value(s). There are four elements that make up aui:condition:
- the dotted-path
fieldname within the root field that makes up the left-side of the condition; - the hard-coded
value(single or list) that makes up the right-side of the condition; - the
operatorthat controls how the left and right sides of the condition are compared; and - the
childrenarray that defines the "grid elements" to display if the condition passes.
A ui:condition uses one of three operators when deciding if a condition passes:
- The
alloperator will pass when the right-side and left-side contains all the same value(s); - the
someoperator will pass when the right-side and left-side contain as least one value in common; - the
noneoperator will pass when the right-side and left-side do not contain any values in common. E.g. (as JSON objects):
Here is how to render an if-then-else for field2 which is an enum that has 3 known values and supports allowing
any other value:
{
"ui:row": [
{
"ui:condition": {
"field": "field2",
"operator": "all",
"value": "value1",
"children": [
{ "ui:row": [...] }
],
}
},
{
"ui:condition": {
"field": "field2",
"operator": "some",
"value": ["value2", "value3"],
"children": [
{ "ui:row": [...] }
],
}
},
{
"ui:condition": {
"field": "field2",
"operator": "none",
"value": ["value1", "value2", "value3"],
"children": [
{ "ui:row": [...] }
]
}
}
]
}Packages Docs Docs Api Reference Dynamic Ui Schema Examples (`packages/docs/docs/api-reference/dynamic-ui-schema-examples.md`)
Dynamic uiSchema Examples
Backward Compatibility Examples
Example 1: Traditional Static uiSchema (No Changes Required)
import { UiSchema } from '@rjsf/utils';
// This continues to work exactly as before
const uiSchema: UiSchema = {
guests: {
items: {
name: { 'ui:placeholder': 'Enter guest name' },
age: { 'ui:widget': 'updown' },
relationship: { 'ui:widget': 'select' },
},
},
};Example 2: Dynamic uiSchema with Function
/* Detailed source-code truncated for AI context efficiency. */Example 3: Using Form Context
import { UiSchema, FormContextType } from '@rjsf/utils';
interface ParticipantData {
name?: string;
email?: string;
workshop?: string;
}
interface MyFormContext extends FormContextType {
eventType?: 'conference' | 'workshop' | 'webinar';
}
const uiSchema: UiSchema<any, any, MyFormContext> = {
participants: {
items: (itemData: ParticipantData | undefined, index: number, formContext?: MyFormContext): UiSchema => {
// Access form-wide settings
const isConference = formContext?.eventType === 'conference';
return {
name: { 'ui:placeholder': 'Participant name' },
email: { 'ui:widget': 'email' },
// Show workshop selection only for conference events
workshop: isConference ? { 'ui:widget': 'select' } : { 'ui:widget': 'hidden' },
};
},
},
};Example 4: Falsy Return Values
import { UiSchema, FormContextType } from '@rjsf/utils';
interface ItemData {
needsCustomUI?: boolean;
field1?: string;
field2?: string;
}
const uiSchema: UiSchema = {
items: {
items: (itemData: ItemData | undefined, index: number): UiSchema | null | undefined => {
// Only apply custom UI to specific items
if (itemData?.needsCustomUI) {
return {
field1: { 'ui:widget': 'textarea' },
field2: { 'ui:help': 'This item needs special attention' },
};
}
// Return null or undefined to use default UI rendering
// This is useful for conditionally applying custom UI
return null;
},
},
};Example 5: Dynamic UI for Fixed Arrays
For fixed/tuple arrays (where schema.items is an array), the dynamic function can be applied to each position:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
interface DetailsData {
age?: number;
role?: string;
}
const schema: RJSFSchema = {
type: 'array',
items: [
{ type: 'string', title: 'First Name' },
{ type: 'string', title: 'Last Name' },
{ type: 'object', title: 'Details', properties: { age: { type: 'number' }, role: { type: 'string' } } },
],
};
const uiSchema: UiSchema = {
items: [
{ 'ui:placeholder': 'Enter first name' }, // Static UI for first item
{ 'ui:placeholder': 'Enter last name' }, // Static UI for second item
// Dynamic UI for third item based on its data
(itemData: DetailsData | undefined, index: number): UiSchema => {
if (itemData?.role === 'admin') {
return {
age: { 'ui:widget': 'hidden' },
role: { 'ui:help': 'Admin role selected' },
};
}
return {
age: { 'ui:widget': 'updown' },
role: { 'ui:widget': 'select' },
};
},
],
};Schema Example
import { RJSFSchema } from '@rjsf/utils';
const schema: RJSFSchema = {
type: 'object',
properties: {
guests: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string', title: 'Name' },
age: { type: 'number', title: 'Age' },
relationship: {
type: 'string',
title: 'Relationship',
enum: ['adult', 'child', 'senior'],
},
guardianName: { type: 'string', title: 'Guardian Name' },
mealPreference: {
type: 'string',
title: 'Meal Preference',
enum: ['vegetarian', 'vegan', 'standard', 'gluten-free'],
},
},
required: ['name', 'relationship'],
},
},
},
};Key Benefits
- Backward Compatible: Existing forms with object-based
uiSchema.itemscontinue to work without any changes - Progressive Enhancement: Developers can opt-in to dynamic behavior when needed
- Flexible: Access to item data, index, and form context enables complex UI logic
- Safe: Built-in error handling prevents the entire form from crashing if your function throws an error. When an error occurs for a specific item, it will be caught and logged to the developer console, and the UI for that item will fall back to the default rendering. This ensures the rest of the form remains functional while making debugging easier.
- On-Demand Execution: The function is executed on-demand during the render cycle. However, as it runs for each array item, performance should be carefully managed for large lists (see Performance Considerations below).
Key Behaviors
- Falsy Returns: If your function returns a falsy value (e.g.,
nullorundefined), the UI for that specific item will fall back to its default rendering. This allows you to conditionally apply custom UI only when needed. - Error Handling: If your function throws an error, it will be caught and logged to the console. The form will continue to work, using default UI for the affected item.
- New Items: When a new item is added to the array,
itemDatawill beundefinedor contain default values from the schema. Always use optional chaining (?.) to safely access properties.
Performance Considerations
When using dynamic uiSchema.items functions, keep in mind:
- The function is executed on every render for each array item
- For large arrays, this can impact performance if the function performs expensive operations
- Best practices:
- Keep the function logic lightweight and fast
- Avoid heavy computations or external API calls within the function
- Consider memoizing results if the same inputs produce the same outputs
- For complex logic, pre-compute values and store them in formContext or component state
Example of a performance-optimized approach:
import React, { PropsWithChildren, useMemo } from 'react';
import Form from '@rjsf/core';
import { RJSFSchema, UiSchema, FormContextType, IChangeEvent } from '@rjsf/utils';
interface ItemData {
type?: string;
field?: any;
}
interface ExpensiveDataConfig {
widget: string;
}
interface MyFormProps {
schema: RJSFSchema;
formData?: any;
}
// In your React component that renders the form:
function MyFormComponent({ schema, formData }: PropsWithChildren<MyFormProps>) {
// Pre-compute expensive data once, and only re-compute if dependencies change
const expensiveData = useMemo<Record<string, ExpensiveDataConfig>>(() => computeExpensiveData(), [/* dependencies */]);
const defaultConfig: ExpensiveDataConfig = { widget: 'text' };
// Define the uiSchema inside the component so it can access the memoized data
const uiSchema: UiSchema = {
myArrayField: { // Target your specific array field
items: (itemData: ItemData | undefined, index: number, formContext?: FormContextType): UiSchema => {
// Use the pre-computed data - this is very fast
const config = expensiveData[itemData?.type || ''] || defaultConfig;
return {
field: { 'ui:widget': config.widget }
};
}
}
};
return <Form schema={schema} uiSchema={uiSchema} formData={formData} />;
}
// Placeholder for the expensive computation function
declare function computeExpensiveData(): Record<string, ExpensiveDataConfig>;Packages Docs Docs Api Reference Form Props (`packages/docs/docs/api-reference/form-props.md`)
title: Props
<Form /> props
acceptCharset
The value of this prop will be passed to the accept-charset HTML attribute on the form.
action
The value of this prop will be passed to the action HTML attribute on the form.
Note that this just renders the action attribute in the HTML markup. There is no real network request being sent to this action on submit. Instead, react-jsonschema-form catches the submit event with event.preventDefault() and then calls the onSubmit function, where you could send a request programmatically with fetch or similar.
autoComplete
The value of this prop will be passed to the autocomplete HTML attribute on the form.
className
The value of this prop will be passed to the class HTML attribute on the form.
children
You can provide custom buttons to your form via the Form component's children. If no children are provided, by default a Submit button will be rendered.
For other ways to modify the default Submit button, see both the Submit Button Options and the SubmitButton Template documentation.
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'string',
};
render(
<Form schema={schema} validator={validator}>
<div>
<button type='submit'>Submit</button>
<button type='button'>Cancel</button>
</div>
</Form>,
document.getElementById('app'),
);Warning: There needs to be a button or an input with
type="submit"to trigger the form submission (and then the form validation).
customValidate
Formerly the validate prop.
The customValidate prop requires a function that specifies custom validation rules for the form.
See Validation for more information.
experimental_componentUpdateStrategy
Experimental feature to specify an alternative component update strategy that accepts one of the following value:
React's default Component rendering strategy is to re-render on every state change, see shouldComponentUpdate docs.PureComponent's strategy uses shallow equality. One can also always update (not recommended for performance reasons, but can be useful for testing)
| Option | Description |
|---|---|
| customDeep | Legacy behavior - uses RJSF's deepEquals function |
| shallow | shallow equality |
| always | component always rerenders |
experimental_defaultFormStateBehavior
Experimental features to specify different form state behavior.
Currently, this only affects the handling of optional array fields where minItems is set and handling of setting defaults based on the value of emptyObjectFields.
Warning: This API is experimental and unstable, therefore breaking changes may be shipped in minor or patch releases. If you want to use this feature, we recommend pinning exact versions of
@rjsf/\*packages in your package.json file or be ready to update your use of it when necessary.
The following subsections represent the different keys in this object, with the tables explaining the values and their meanings.
arrayMinItems
This optional subsection is an object with two optional fields, populate and mergeExtraDefaults.
When not specified, it defaults to { populate: 'all', mergeExtraDefaults: false }.
arrayMinItems.populate
Optional enumerated flag controlling how array minItems are populated, defaulting to all:
| Flag Value | Description |
|---|---|
all |
Legacy behavior - populate minItems entries with default values initially and include empty array when no values have been defined. |
requiredOnly |
Ignore minItems on a field when calculating defaults unless the field is required. |
never |
Ignore minItems on a field when calculating defaults for required and non-required. Value will set only if defined default and from formData |
arrayMinItems.computeSkipPopulate
The signature and documentation for this property is as follow:
computeSkipPopulate <T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
A function that determines whether to skip populating the array with default values based on the provided validator, schema, and root schema.
If the function returns true, the array will not be populated with default values.
If the function returns false, the array will be populated with default values according to the populate option.
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that is used to detect valid schema conditions - schema: S - The schema for which resolving a condition is desired
- [rootSchema]: S - The root schema that will be forwarded to all the APIs
Returns
- boolean: A boolean indicating whether to skip populating the array with default values.
Example
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
stringArray: {
type: 'array',
items: { type: 'string' },
minItems: 1,
},
numberArray: {
type: 'array',
items: { type: 'number' },
minItems: 1,
},
},
required: ['stringArray', 'numberArray'],
};
const computeSkipPopulateNumberArrays = (validator, schema, rootSchema) =>
// These conditions are needed to narrow down the type of the schema.items
!Array.isArray(schema?.items) &&
typeof schema?.items !== 'boolean' &&
schema?.items?.type === 'number',
render(
<Form
schema={schema}
validator={validator}
experimental_defaultFormStateBehavior={{
arrayMinItems: {
computeSkipPopulate: computeSkipPopulateNumberArrays,
},
}}
/>,
document.getElementById('app')
);arrayMinItems.mergeExtraDefaults
Optional boolean flag, defaulting to false when not specified.
When formData is provided and does not contain minItems worth of data, this flag controls whether the extra data provided by the defaults is appended onto the existing formData items to ensure the minItems condition is met.
When false (legacy behavior), only the formData provided is merged into the default form state, even if there are fewer than the minItems.
When true, the defaults are appended onto the end of the formData until the minItems condition is met.
emptyObjectFields
Optional enumerated flag controlling how empty object fields are populated, defaulting to populateAllDefaults:
| Flag Value | Description |
|---|---|
populateAllDefaults |
Legacy behavior - set default when there is a primitive value, an non-empty object field, or the field itself is required |
populateRequiredDefaults |
Only sets default when a value is an object and its parent field is required, or it is a primitive value and it is required |
skipDefaults |
Does not set defaults |
skipEmptyDefaults |
Does not set an empty default. It will still apply the default value if a default property is defined in your schema |
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
items: { type: 'string' },
minItems: 3,
};
render(
<Form
schema={schema}
validator={validator}
experimental_defaultFormStateBehavior={{
emptyObjectFields: 'populateRequiredDefaults',
}}
/>,
document.getElementById('app'),
);allOf
Optional enumerated flag controlling how empty defaults are populated when allOf schemas are provided, defaulting to skipDefaults:
| Flag Value | Description |
|---|---|
skipDefaults |
Skip parsing defaults from allOf schemas nested inside the schema defaults are computed from, with the exceptions below |
populateDefaults |
Generate default values for properties in the allOf schema including if-then-else syntax |
skipDefaults only skips the allOf schemas nested inside the schema that defaults are computed from, not that schema's own allOf.
Which schema that is depends on what the form is doing:
- When the form computes defaults from the root schema, a root-level
allOfprovides its defaults with either value. - Some actions compute defaults from a subschema as if it were the root, such as adding an array item or optional data, or switching a
oneOforanyOfoption, so that subschema's ownallOfprovides its defaults with either value. When switching options, though, theifof anif-then-elsein the new option'sallOfis checked against the data of the option being left, so underskipDefaultsitsthendefault is filled in only when that data matches theif. - The option picked on the initial render is not computed as if it were the root, even when its
oneOforanyOfis in the root schema, so underskipDefaultsitsallOfis left out until the user switches away from that option and back.
The branch of an if-then-else is picked from the form data, not from the computed defaults, except in a dependencies entry, as the last item below says:
- When the
iflists a property inrequiredand only a default provides that property, thethendefault is left out until the form data holds the value, for instance on the initial render. - Without
required, a missing property still satisfies theif'sproperties, so such anifpasses with no data, and itsthendefault is filled in even when theifdoes not match the defaulted value. - With one
allOfentry perenumvalue and no form data, the defaultallOfmerger merges thethendefaults of all the entries, and the first entry that defaults a property wins. Anexperimental_customMergeAllOfthat throws on the conflictingdefaults drops the wholeallOfinstead.
An allOf in an object property or in an array's items is skipped as a whole, plain property defaults included, so it usually needs populateDefaults to provide its defaults.
This is specific to allOf:
- An
if-then-elseplaced directly in a nested object schema is resolved with either value, unlessemptyObjectFieldsisskipEmptyDefaults. For example, underskipDefaults,items: { type: 'object', if, then }fills in thethendefault, whileitems: { type: 'object', allOf: [{ if, then }] }does not. - Adding a direct
ifto thatitemsschema resolves its wholeallOftoo, unlessemptyObjectFieldsisskipEmptyDefaults. - With an
experimental_customMergeAllOfbuilt on a deep merger, such ascreateDeepAllOfMergefrom@x0k/json-schema-mergegiven a shallow merge built with that library'screateMergerandcreateShallowAllOfMerge, merging anallOfalso turns a property'sallOf: [{ if, then }]into a directif-then-else, so that property'sthendefault is filled in underskipDefaults, unlessemptyObjectFieldsisskipEmptyDefaults. That happens wherever anallOfis merged: the root's ownallOf, or theallOfof an object oritemsschema that also has a directif, but not a nestedallOfon its own. - A
dependenciesentry in a nested object schema is resolved once its property has a value, itsallOfandif-then-elseincluded, even whenemptyObjectFieldsisskipEmptyDefaults. A default counts as that value, and the entry'sifis checked against it, so anifthat lists the property inrequiredpasses with no form data, while one that does not match the default fails. For example, underskipDefaults,items: { type: 'object', properties: { animal: { default: 'Cat' } }, dependencies: { animal: { allOf: [{ if, then }] } } }fills in thethendefault. A rootdependenciesentry counts a default only while the form data is empty: once the form data holds any value, the entry is applied only when the form data holds its property.
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'Example',
type: 'object',
properties: {
animalInfo: {
properties: {
animal: {
type: 'string',
default: 'Cat',
enum: ['Cat', 'Fish'],
},
},
allOf: [
{
if: {
properties: {
animal: {
const: 'Cat',
},
},
},
then: {
properties: {
food: {
type: 'string',
default: 'meat',
enum: ['meat', 'grass', 'fish'],
},
},
required: ['food'],
},
},
],
},
},
};
render(
<Form
schema={schema}
validator={validator}
experimental_defaultFormStateBehavior={{
allOf: 'populateDefaults',
}}
/>,
document.getElementById('app'),
);constAsDefaults
Optional enumerated flag controlling how const values are merged into the form data as defaults when dealing with undefined values, defaulting to always.
The defaulting behavior for this flag will always be controlled by the emptyObjectField flag value.
For instance, if populateRequiredDefaults is set and the const value is not required, it will not be set.
| Flag Value | Description |
|---|---|
always |
A const value will always be merged into the form as a default. If there is are const values in a oneOf (for instance to create an enumeration with title different from the values), the first const value will be defaulted |
skipOneOf |
If const is in a oneOf it will NOT pick the first value as a default |
never |
A const value will never be used as a default |
mergeDefaultsIntoFormData
Optional enumerated flag controlling how the defaults are merged into the form data when dealing with undefined values, defaulting to useFormDataIfPresent.
NOTE: If there is a default for a field and the formData is unspecified, the default ALWAYS merges.
| Flag Value | Description |
|---|---|
useFormDataIfPresent |
Legacy behavior - Do not merge defaults if there is a value for a field in formData even if that value is explicitly set to undefined |
useDefaultIfFormDataUndefined |
If the value of a field within the formData is undefined, then use the default value instead |
nestedDefaultsPrecedence
Optional enumerated flag controlling how defaults defined on multiple levels are merged together for overlapping properties, defaulting to descendantWins.
| Flag Value | Description |
|---|---|
descendantWins |
The innermost (descendant) default value definition takes precedence over its ancestor's defaults |
ancestorWins |
The outermost (ancestor) default value definition takes precedence over any descendant's defaults |
Example
In the following example, the animal property is a descendant of the root schema and both define a default value for animal. By default, the animal's default value Cat would take precedence over its ancestor's Fish. However, since nestedDefaultsPrecedence is set to ancestorWins, the root schema's default value takes precedence and animal is set to Fish by default.
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
default: {
animal: 'Fish',
},
properties: {
animal: {
type: 'string',
default: 'Cat',
enum: ['Cat', 'Fish'],
},
},
};
render(
<Form
schema={schema}
validator={validator}
experimental_defaultFormStateBehavior={{
nestedDefaultsPrecedence: 'ancestorWins',
}}
/>,
document.getElementById('app'),
);requiredBooleanDefault
Optional enumerated flag controlling whether a boolean listed in its parent's required array, with no default of its own, is populated with false, defaulting to populateFalse.
An explicit schema default, a parent default and an existing formData value always take precedence; this flag only decides what happens when none of them provides a value.
| Flag Value | Description |
|---|---|
populateFalse |
A required boolean with no default is set to false |
skip |
No value is synthesized; the property stays undefined until the user answers it, so required remains a validation concern |
Example
In the following example, agree is required but has no default. By default it would start as false, and the form would report { agree: false } through onChange on mount. With requiredBooleanDefault set to skip, formData stays {} until the user answers, and validation reports agree as missing until then. This is the behavior to choose when a boolean question is rendered with an explicit "unanswered" state, for example a - - - / Yes / No select, rather than a checkbox.
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
agree: {
type: 'boolean',
title: 'Do you agree?',
},
},
required: ['agree'],
};
render(
<Form
schema={schema}
validator={validator}
experimental_defaultFormStateBehavior={{
requiredBooleanDefault: 'skip',
}}
/>,
document.getElementById('app'),
);experimental_customMergeAllOf
The experimental_customMergeAllOf function allows you to provide a custom implementation for merging allOf schemas. This can be particularly useful in case the where the default merge library (@x0k/json-schema-merge) doesn't satisfy your functional or performance requirements.
By providing your own implementation, you can potentially achieve significant performance improvements. For instance, if your use case only requires a subset of JSON Schema features, you can implement a faster, more tailored merging strategy.
If you're looking for alternative allOf merging implementations, you might consider allof-merge.
Warning: This is an experimental feature. Only use this if you fully understand the implications of custom allOf merging and are prepared to handle potential edge cases. Incorrect implementations may lead to unexpected behavior or validation errors.
import { Form } from '@rjsf/core';
import validator from '@rjsf/validator-ajv8';
const customMergeAllOf = (schema: RJSFSchema): RJSFSchema => {
// Your custom implementation here
};
render(
<Form schema={schema} validator={validator} experimental_customMergeAllOf={customMergeAllOf} />,
document.getElementById('app'),
);disabled
It's possible to disable the whole form by setting the disabled prop. The disabled prop is then forwarded down to each field of the form.
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'string',
};
render(<Form schema={schema} validator={validator} disabled />, document.getElementById('app'));If you just want to disable some fields, see the ui:disabled parameter in uiSchema.
readonly
It's possible to make the whole form read-only by setting the readonly prop. The readonly prop is then forwarded down to each field of the form.
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'string',
};
render(<Form schema={schema} validator={validator} readonly />, document.getElementById('app'));If you just want to make some fields read-only, see the ui:readonly parameter in uiSchema.
enctype
The value of this prop will be passed to the enctype HTML attribute on the form.
extraErrors
This prop allows passing in custom errors that are augmented with the existing JSON Schema errors on the form; it can be used to implement asynchronous validation.
By default, these are non-blocking errors, meaning that you can still submit the form when these are the only errors displayed to the user.
See Validation for more information.
extraErrorsBlockSubmit
If set to true, causes the extraErrors to become blocking when the form is submitted.
fields
Dictionary of registered fields in the form. See Custom Widgets and Fields for more information.
focusOnFirstError
If set to true, then the first field with an error will receive the focus when the form is submitted with errors.
You can also provide a custom callback function to handle what happens when this function is called.
import { Form } from '@rjsf/core';
import { RJSFSchema, RJSFValidationError } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'string',
};
const focusOnError = (error: RJSFValidationError) => {
console.log('I need to handle focusing this error');
};
render(<Form schema={schema} validator={validator} focusOnFirstError={focusOnError} />, document.getElementById('app'));formContext
You can provide a formContext object to the Form, which is passed down to all fields and widgets. Useful for implementing context aware fields and widgets.
See AntD Customization for formContext customizations for the antd theme.
See Semantic UI Customization for formContext customizations for the semantic-ui theme.
formData
The data for the form, used to load a "controlled" form with its current data. If you want an "uncontrolled" form with initial data, then use initialFormData instead.
id
The value of this prop will be passed to the id HTML attribute on the form.
idPrefix
To avoid collisions with existing ids in the DOM, it is possible to change the prefix used for ids (the default is root).
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'string',
};
render(<Form schema={schema} validator={validator} idPrefix={'rjsf_prefix'} />, document.getElementById('app'));This will render instead of
idSeparator
To avoid using a path separator that is present in field names, it is possible to change the separator used for ids (the default is _).
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
first: {
type: 'string',
},
},
};
render(<Form schema={schema} validator={validator} idSeparator={'/'} />, document.getElementById('app'));This will render instead of when rendering first.
initialFormData
The initial data for the form, used to fill an "uncontrolled" form with existing data on the initial render and when reset() is called programmatically.
nameGenerator
The nameGenerator prop allows you to customize how HTML name attributes are generated for form fields. This is essential when submitting form data to backend frameworks that expect specific naming conventions for structured data.
Default behavior: When no nameGenerator is provided, the name attribute will equal the id attribute (e.g., root_tasks_0_title).
RJSF provides two built-in generators:
bracketNameGenerator - Generates bracket notation for PHP/Rails (e.g., root[tasks][0][title]). Automatically appends [] for multi-value fields like checkboxes.
dotNotationNameGenerator - Generates dot notation for other frameworks (e.g., root.tasks.0.title).
import { Form } from '@rjsf/core';
import { bracketNameGenerator, RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
firstName: { type: 'string' },
tasks: {
type: 'array',
items: {
type: 'object',
properties: {
title: { type: 'string' },
},
},
},
},
};
render(
<Form schema={schema} validator={validator} nameGenerator={bracketNameGenerator} />,
document.getElementById('app'),
);You can also create a custom generator by implementing the NameGeneratorFunction type, which receives path (array of path segments), idPrefix (typically 'root'), and optional isMultiValue (boolean for multi-value fields).
liveOmit
Flag that describes when live omit will be performed. Live omit happens only when omitExtraData is also set to
to true and the form's data is updated by the user.
If no value (or false) is provided, then live omit will not happen. If true or onChange is provided for
the flag, then live omit will be performed after processing of all pending changes has completed. If onBlur
is provided, then live omit will be performed when a field that was updated is blurred (as a performance
optimization).
NOTE: The
booleanoptions for this flag is deprecated and will be removed in a future major release
liveValidate
Flag that describes when live validation will be performed. Live validation means that the form will perform
validation and show any validation errors whenever the form data is updated, rather than just on submit.
If no value (or false) is provided, then live validation will not happen. If true or onChange is provided for
the flag, then live validation will be performed after processing of all pending changes has completed. If onBlur
is provided, then live validation will be performed when a field that was updated is blurred (as a performance
optimization).
NOTE: The
booleanoptions for this flag is deprecated and will be removed in a future major release
method
The value of this prop will be passed to the method HTML attribute on the form.
name
The value of this prop will be passed to the name HTML attribute on the form.
noHtml5Validate
If set to true, turns off HTML5 validation on the form. Set to false by default.
noValidate
If set to true, turns off all validation. Set to false by default.
NOTE: In a future major release, this flag may be deleted replaced by making
validatorprop optional
omitExtraData
If set to true, then extra form data values that are not in any form field will be removed whenever onSubmit is called. Set to false by default.
onBlur
Sometimes you may want to trigger events or modify external state when a field has been touched, so you can pass an onBlur handler, which will receive the id of the input that was blurred and the field value.
onChange
If you plan on being notified every time the form data are updated, you can pass an onChange handler, which will receive the same first argument as onSubmit any time a value is updated in the form.
It will also receive, as the second argument, the id of the field which experienced the change.
Generally, this will be the id of the field for which input data is modified.
In the case of adding/removing of new fields in arrays or objects with additionalProperties or patternProperties and the rearranging of items in arrays, the id will be that of the array or object itself, rather than the item/field being added, removed or moved.
onError
To react when submitted form data are invalid, pass an onError handler. It will be passed the list of encountered errors:
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'string',
};
const onError = (errors) => console.log('I have', errors.length, 'errors to fix');
render(<Form schema={schema} validator={validator} onError={onError} />, document.getElementById('app'));onFocus
Sometimes you may want to trigger events or modify external state when a field has been focused, so you can pass an onFocus handler, which will receive the id of the input that is focused and the field value.
onSubmit
You can pass a function as the onSubmit prop of your Form component to listen to when the form is submitted and its data are valid.
It will be passed a result object having a formData attribute, which is the valid form data you're usually after.
The original event will also be passed as a second parameter:
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'string',
};
const onSubmit = ({ formData }, e) => console.log('Data submitted: ', formData);
render(<Form schema={schema} validator={validator} onSubmit={onSubmit} />, document.getElementById('app'));Note: If there are fields in the
formDatathat are not represented in the schema, they will be retained by default. If you would like to remove those extra values on form submission, you may need to set theomitExtraDataand/orliveOmitprops.
removeEmptyOptionalObjects
Deprecated: This prop no longer has any effect and will be removed in a future release. The behavior of pruning optional empty objects is now built into
omitExtraData— enable that prop instead.
When a JSON Schema has a required field inside an optional object, any user interaction with that optional object "activates" it. Even if the user clears all the fields within that object, the empty object property (e.g., { test: {} } or { test: { field1: "" } }) remains in the formData. Because the object contains required fields that are now empty, the form becomes unsubmittable.
Previously, setting removeEmptyOptionalObjects to true caused the form to recursively prune these optional empty objects from the formData during onChange, onBlur, and onSubmit. This pruning is now performed automatically by omitExtraData.
schema
Required! Form schema. We support JSON schema draft-07 by default. See Schema Reference for more information.
showErrorList
When this prop is set to top or bottom, a list of errors (or the custom error list defined in the ErrorList) will also show at the bottom or top of the form. When set to false, only inline input validation errors will be shown. Set to top by default. See Validation for more information.
tagName
It's possible to change the default form tag name to a different HTML tag, which can be helpful if you are nesting forms. However, native browser form behaviour, such as submitting when the Enter key is pressed, may no longer work.
<Form
tagName="div"
...
/>You can also provide a class/function component.
const CustomForm = props => <form {...props} style={...} className={...} />
// ...
<Form
tagName={CustomForm}
...
/>target
The value of this prop will be passed to the target HTML attribute on the form.
templates
Dictionary of registered templates in the form. See Custom Templates for more information.
transformErrors
A function can be passed to this prop in order to make modifications to the default errors resulting from JSON Schema validation. See Validation for more information.
translateString
Optional string translation function, if provided, allows users to change the translation of the RJSF internal strings.
Some strings contain replaceable parameter values as indicated by %1, %2, etc.
The number after the % indicates the order of the parameter.
The ordering of parameters is important because some languages may choose to put the second parameter before the first in its translation. In addition to replaceable parameters, some of the strings support the use of markdown and simple html.
One can use the documentation of the TranslatableString enums to determine which enum values contain replaceable parameters and which support markdown and simple html.
One could use this function to alter one or more of the existing english strings to better suit one's application or fully translate all strings into a different language.
Below is an example of changing a few of the english strings to something else:
import { TranslatableString, englishStringTranslator, replaceStringParameters } from '@rjsf/utils';
function fixupSomeEnglishStrings(stringToTranslate: TranslatableString, params?: string[]): string {
switch (stringToTranslate) {
case TranslatableString.NewStringDefault:
return ''; // Use an empty string for the new additionalProperties string default value
case TranslatableString.KeyLabel:
return replaceStringParameters('%1 Key Name', params); // Add "Name" onto the end of the WrapIfAdditionalTemplate key label
default:
return englishStringTranslator(stringToTranslate, params); // Fallback to the default english
}
}uiSchema
Form uiSchema. See uiSchema Reference for more information.
useFallbackUiForUnsupportedType
If set to true, when an unsupported schema type is encountered, the form will render a fallback UI instead of displaying an error. The fallback UI will display a widget that allows the user to select a JSON Schema primitive type, and a field containing the form data that matches the selected type. Set to false by default.
validator
Required! An implementation of the ValidatorType interface that is needed for form validation to work.@rjsf/validator-ajv8 exports the implementation of this interface from RJSF version 4.
widgets
Dictionary of registered widgets in the form. See Custom Widgets and Fields for more information.
Packages Docs Docs Api Reference UiSchema (`packages/docs/docs/api-reference/uiSchema.md`)
uiSchema
JSON Schema is limited for describing how a given data type should be rendered as a form input component. That's why this library introduces the concept of uiSchema.
A UI schema is basically an object literal providing information on how the form should be rendered, while the JSON schema tells what.
The uiSchema object follows the tree structure of the form field hierarchy, and defines how each property should be rendered.
Note that almost every property within uiSchema can be rendered in one of two ways: {"ui:options": {[property]: [value]}}, or {"ui:[property]": value}.
In other words, the following uiSchemas are equivalent:
{
"ui:title": "Title",
"ui:description": "Description",
"ui:classNames": "my-class",
"ui:submitButtonOptions": {
"props": {
"disabled": false,
"className": "btn btn-info"
},
"norender": false,
"submitText": "Submit"
}
}{
"ui:options": {
"title": "Title",
"description": "Description",
"classNames": "my-class",
"submitButtonOptions": {
"props": {
"disabled": false,
"className": "btn btn-info"
},
"norender": false,
"submitText": "Submit"
}
}
}For a full list of what is supported in the uiSchema see the UiSchema type in @rjsf/utils/types.ts.
Be sure to pay attention to the hierarchical intersection to these other types: UIOptionsBaseType and TemplatesType.
Exceptions to the equivalence
There are 4 properties that exist in a UiSchema that will not be found in an inner ui:options object.
`ui:globalOptions`
The set of globally relevant UiSchema options that are read from the root-level UiSchema and stored in the registry for use everywhere.
import { UiSchema } from '@rjsf/utils';
const uiSchema: UiSchema = {
'ui:globalOptions': { copyable: true },
};`ui:definitions`
The ui:definitions property allows you to define reusable UI customizations for schema $ref references. This is particularly useful for:
- Recursive schemas - Define uiSchema once for a self-referencing schema node
- Reused definitions - Apply consistent UI to schemas used in multiple places
- oneOf/anyOf branches - Provide different uiSchema for branches that reference different definitions
The keys in ui:definitions must match the exact $ref path used in the schema (e.g., #/definitions/address or #/$defs/node).
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
definitions: {
address: {
type: 'object',
properties: {
street_address: { type: 'string' },
city: { type: 'string' },
},
},
node: {
type: 'object',
properties: {
name: { type: 'string' },
children: {
type: 'array',
items: { $ref: '#/definitions/node' }, // Recursive reference
},
},
},
},
type: 'object',
properties: {
billing_address: { $ref: '#/definitions/address' },
shipping_address: { $ref: '#/definitions/address' },
tree: { $ref: '#/definitions/node' },
},
};
const uiSchema: UiSchema = {
'ui:definitions': {
'#/definitions/address': {
street_address: { 'ui:placeholder': 'Street and number' },
city: { 'ui:placeholder': 'City name' },
},
'#/definitions/node': {
name: { 'ui:placeholder': 'Enter node name' },
children: { 'ui:options': { orderable: false } },
},
},
// Local overrides take precedence over ui:definitions
shipping_address: {
street_address: { 'ui:placeholder': 'Shipping street (overrides definition)' },
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));Local Overrides
You can override specific properties from ui:definitions by providing values at the field path. Local values are merged with definitions, with local values taking precedence.
oneOf/anyOf with Same Property Names
When using oneOf or anyOf with branches that have properties with the same name, each branch's $ref maps to its own entry in ui:definitions, ensuring correct UI is applied:
const schema: RJSFSchema = {
definitions: {
person: { type: 'object', properties: { name: { type: 'string' } } },
company: { type: 'object', properties: { name: { type: 'string' } } },
},
type: 'object',
properties: {
contact: {
oneOf: [
{ title: 'Person', $ref: '#/definitions/person' },
{ title: 'Company', $ref: '#/definitions/company' },
],
},
},
};
const uiSchema: UiSchema = {
'ui:definitions': {
'#/definitions/person': {
name: { 'ui:placeholder': 'Full name (e.g., John Doe)' },
},
'#/definitions/company': {
name: { 'ui:placeholder': 'Company name (e.g., Acme Inc.)' },
},
},
};`ui:rootFieldId` (deprecated)
DEPRECATED: Use
Form.idPrefixinstead, will be removed in a future major version
By default, this library will generate ids unique to the form for all rendered widgets.
If you plan on using multiple instances of the Form component in a same page, it's wise to declare a root prefix for these, using the ui:rootFieldId uiSchema directive:
import { UiSchema } from '@rjsf/utils';
const uiSchema: UiSchema = {
'ui:rootFieldId': 'myform',
};This will make all widgets have an id prefixed with myform.
`ui:field`
The ui:field property overrides the Field implementation used for rendering any field in the form's hierarchy.
Specify either the name of a field that is used to look up an implementation from the fields list or an actual one-off Field component implementation itself.
See Custom Widgets and Fields for more information about how to use this property.
`ui:fieldReplacesAnyOrOneOf`
By default, any field that is rendered for an anyOf/oneOf schema will be wrapped inside the AnyOfField or OneOfField component.
This default behavior may be undesirable if your custom field already handles behavior related to choosing one or more subschemas contained in the anyOf/oneOf schema.
By providing a true value for this flag in association with a custom ui:field, the wrapped components will be omitted, so just one instance of the custom field will be rendered.
If the flag is omitted or set to false, your custom field will be wrapped by AnyOfField/OneOfField.
`ui:options`
The ui:options property cannot be nested inside itself and thus is the last exception.
`ui:XXX` or `ui:options.XXX`
All the properties that follow can be specified in the uiSchema in either of the two equivalent ways.
NOTE: The properties specific to array items can be found here. For advanced dynamic UI schema capabilities for array items, see the Dynamic UI Schema Examples.
widget
The ui:widget property overrides the Widget implementation used for rendering any field in the form's hierarchy.
Specify either the name of a widget that is used to look up an implementation from the widgets list or an actual one-off Widget component implementation itself.
See Custom Widgets and Fields for more information about how to use this property.
classNames
The uiSchema object accepts a ui:classNames property for each field of the schema:
import { UiSchema } from '@rjsf/utils';
const uiSchema = {
title: {
'ui:classNames': 'task-title foo-bar',
},
};Will result in:
<div class="field field-string task-title foo-bar">
<label>
<span>Title*</span>
<input value="My task" required="" type="text" />
</label>
</div>style
The uiSchema object accepts a ui:style property for each field of the schema:
import { UiSchema } from '@rjsf/utils';
const uiSchema = {
title: {
'ui:style': { color: 'red' },
},
};Will result in:
<div class="field field-string task-title" style={{ color: "red" }}>
<label>
<span>Title*</span>
<input value="My task" required="" type="text">
</label>
</div>allowClearTextInputs
The optional ui:allowClearTextInputs uiSchema directive enables a clear/reset button for text-based input widgets.
When set to true, a clear button will be displayed when the input field has a value and is not readonly or disabled.
When omitted, no clear button will be displayed for text input fields.
When clicked, the property value will be set to the ui:emptyValue, if defined.
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:allowClearTextInputs': true,
};It can also be enabled globally by setting the allowClearTextInputs option to true in the ui:globalOptions
uiSchema directive.
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:globalOptions': {
allowClearTextInputs: true,
},
};autocomplete
If you want to mark a text input, select or textarea input to use the HTML autocomplete feature, set the ui:autocomplete uiSchema directive to a valid HTML autocomplete value.
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:widget': 'textarea',
'ui:autocomplete': 'on',
};autocapitalize
To control automatic capitalization on virtual keyboards for a text input, set the ui:autocapitalize uiSchema
directive to a valid HTML autocapitalize value.
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:autocapitalize': 'words',
};autofocus
If you want to automatically focus on a text input or textarea input, set the ui:autofocus uiSchema directive to true.
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:widget': 'textarea',
'ui:autofocus': true,
};description
Sometimes it's convenient to change the description of a field. This is the purpose of the ui:description uiSchema directive:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:widget': 'password',
'ui:description': 'The best password',
};deprecatedHandling
The ui:deprecatedHandling uiSchema directive controls how a field marked as deprecated in the JSON Schema is rendered.
Accepts one of three values:
'label'(default): The field is rendered normally with"(deprecated)"appended to its label.'disable': The field is rendered but all its child widgets are disabled.'hide': The field is completely hidden from the form.
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = {
type: 'object',
properties: {
legacyField: { type: 'string', deprecated: true },
},
};
const uiSchema: UiSchema = {
legacyField: {
'ui:options': {
deprecatedHandling: 'disable',
},
},
};It can also be set globally by specifying the deprecatedHandling option in the ui:globalOptions uiSchema directive, which applies the chosen behavior to every deprecated field in the form.
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
legacyField: { type: 'string', deprecated: true },
anotherOldField: { type: 'number', deprecated: true },
},
};
const uiSchema: UiSchema = {
'ui:globalOptions': {
deprecatedHandling: 'hide',
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));disabled
The ui:disabled uiSchema directive will disable all child widgets from a given field.
Note: If you're wondering about the difference between a
disabledfield and areadonlyone: Marking a field as read-only will render it greyed out, but its text value will be selectable. Disabling it will prevent its value to be selected at all.
enableMarkdownInDescription
The ui:enableMarkdownInDescription uiSchema directive enables the support of Markdown syntax within the description of
a field.
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = { type: 'string', description: '**bolded** text in the description' };
const uiSchema: UiSchema = {
'ui:enableMarkdownInDescription': true,
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));It can also be enabled globally by setting the enableMarkdownInDescription option to true in the ui:globalOptions
uiSchema directive.
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = { type: 'string', description: '**bolded** text in the description' };
const uiSchema: UiSchema = {
'ui:globalOptions': {
enableMarkdownInDescription: true,
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));enableMarkdownInHelp
The ui:enableMarkdownInHelp uiSchema directive enables the support of Markdown syntax within the help displayed for
a field.
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:enableMarkdownInHelp': true,
'ui:help': '**bolded** text in the help',
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));It can also be enabled globally by setting the enableMarkdownInHelp option to true in the ui:globalOptions
uiSchema directive.
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:globalOptions': {
enableMarkdownInHelp: true,
},
'ui:help': '**bolded** text in the help',
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));enableOptionalDataFieldForType
The ui:enableOptionalDataFieldForType uiSchema directive enables support for displaying the Optional Data Controls feature.
The intention of this feature is to allow developers to provide a condensed UI for users who don't care to enter an optional list of array items or set of optional object fields (see examples below).
This directive takes, as its value, an array in one of four forms:
[]- Disables the feature at a global or field level['array']- Enables the feature only for optional arrays at a global or field level['object']- Enables the feature only for optional object at a global or field level['array', 'object']- Enables the feature for both optional object and arrays at a global or field level
It can be specified in either the ui:globalOptions to turn the feature on for everything or in a specific field's uiSchema
To work properly this option must be coupled with the emptyObjectFields experimental feature on Form using the populateRequiredDefaults or skipDefaults options.
When enabled for either (or both) the array or object types, any optional object or array field which has an "undefined" value in formData will NOT render any of the container's UI elements.
Instead the object/array container's field title will have an "Add optional data" icon button that, when clicked will cause an empty container data element to be added to formData.
When enabled for either (or both) the array or object types, any optional object or array field which has an "defined" value in formData will render all of the container's UI elements as normal AND the object/array container's field title will have a "Remove optional data" icon button that, when clicked will set the data for field in the formData to "undefined".
Here is an example of what the UI will look like when enabled using the following Form configuration:
const schema: RJSFSchema = {
title: 'test',
properties: {
nestedObjectOptional: {
type: 'object',
properties: {
test: {
type: 'string',
},
},
},
nestedArrayOptional: {
type: 'array',
items: {
type: 'string',
},
},
},
};
const uiSchema = {
'ui:globalOptions': {
enableOptionalDataFieldForType: ['object', 'array'],
},
};
const experimental_defaultFormStateBehavior = {
// Set the emptyObjectFields to only populate required defaults to highlight the code working
emptyObjectFields: 'populateRequiredDefaults',
};
render(
<Form
schema={schema}
validator={validator}
uiSchema={uiSchema}
experimental_defaultFormStateBehavior={experimental_defaultFormStateBehavior}
templates={{ OptionalDataControlsTemplate }}
/>,
document.getElementById('app'),
);Add Optional Data Controls
Remove Optional Data Controls
emptyValue
The ui:emptyValue uiSchema directive provides the value to store when the input for a field is emptied, whether by typing or by clicking the ui:allowClearTextInputs clear button. It defaults to undefined, which omits the field from the form data entirely.
enumDisabled
To disable an option, use the enumDisabled property in uiSchema.
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = {
type: 'string',
enum: ['one', 'two', 'three'],
};
const uiSchema: UiSchema = {
'ui:enumDisabled': ['two'],
};enumNames
Allows a user to provide labels for enum values in the schema. Can be an array (matched by index) or a map (matched by value).
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = {
type: 'number',
enum: [1, 2, 3],
};
// Array form (matched by index)
const uiSchemaArray: UiSchema = {
'ui:enumNames': ['one', 'two', 'three'],
};
// Map form (matched by value)
const uiSchemaMap: UiSchema = {
'ui:enumNames': { 1: 'one', 2: 'two', 3: 'three' },
};enumOrder
Controls the display order of enum options. Use '*' to represent remaining values in their original schema order. Unlisted values not covered by '*' are dropped.
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = {
type: 'string',
enum: ['apple', 'banana', 'cherry', 'date'],
};
const uiSchema: UiSchema = {
'ui:enumOrder': ['cherry', '*', 'apple'],
};filePreview
The FileWidget can be configured to show a preview of an image or a download link for non-images using this flag.
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = {
type: 'string',
format: 'data-url',
};
const uiSchema: UiSchema = {
'ui:options': {
filePreview: true,
},
};help
Sometimes it's convenient to add text next to a field to guide the end user filling it. This is the purpose of the ui:help uiSchema directive:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:widget': 'password',
'ui:help': 'Hint: Make it strong!',
};Help texts work for any kind of field at any level, and will always be rendered immediately below the field component widget(s) (after contextualized errors, if any).
hideError
The ui:hideError uiSchema directive will, if set to true, hide the default error display for the given field AND all of its child fields in the hierarchy.
If you need to enable the default error display of a child in the hierarchy after setting hideError: true on the parent field, simply set hideError: false on the child.
This is useful when you have a custom field or widget that utilizes either the rawErrors or the errorSchema to manipulate and/or show the error(s) for the field/widget itself.
inputType
To change the input type (for example, tel or email) you can specify the inputType in the ui:options uiSchema directive.
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:options': {
inputType: 'tel',
},
};label
Field labels are rendered by default.
Labels may be omitted on a per-field by setting the label option to false in the ui:options uiSchema directive.
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:options': {
label: false,
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));They can also be omitted globally by setting the label option to false in the ui:globalOptions uiSchema directive.
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:globalOptions': {
label: false,
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));optionValueFormat
Controls how enum-backed widgets (select, radio, checkboxes) encode option values in their DOM value attributes. Accepts 'indexed' (default) or 'realValue'.
'indexed': options are encoded as their array index (e.g.value="0",value="1"). This is the historical behavior and keeps non-primitive enum values (objects, arrays) addressable without stringifying them.'realValue': primitive option values are stringified directly (e.g.value="admin",value="42",value="true"). This enables native HTML form submission and browser autocomplete since the submitted value matches the enum value. Non-primitive values (objects, arrays) still fall back to their index becauseString(obj)would produce"[object Object]".
The form data passed to onChange is always the typed enum value; this option only affects the DOM-level encoding. Can be specified in ui:globalOptions to apply to all enum-backed fields, or per-field in ui:options.
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
role: { type: 'string', enum: ['admin', 'editor', 'viewer'] },
},
};
// Form-wide
const uiSchema: UiSchema = {
'ui:globalOptions': {
optionValueFormat: 'realValue',
},
};
// Or per-field
const fieldUiSchema: UiSchema = {
role: {
'ui:options': {
optionValueFormat: 'realValue',
},
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));order
This property allows you to reorder the properties that are shown for a particular object. See Objects for more information.
placeholder
You can add placeholder text to an input by using the ui:placeholder uiSchema directive:
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = { type: 'string', format: 'uri' };
const uiSchema: UiSchema = {
'ui:placeholder': 'http://',
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));Fields using enum can also use ui:placeholder. The value will be used as the text for the empty option in the select widget.
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = { type: 'string', enum: ['First', 'Second'] };
const uiSchema: UiSchema = {
'ui:placeholder': 'Choose an option',
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));readonly
The ui:readonly uiSchema directive will mark all child widgets from a given field as read-only. This is equivalent to setting the readOnly property in the schema.
Note: If you're wondering about the difference between a
disabledfield and areadonlyone: Marking a field as read-only will render it greyed out, but its text value will be selectable. Disabling it will prevent its value to be selected at all.
rows
You can set the initial height of a textarea widget by specifying rows option.
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:options': {
widget: 'textarea',
rows: 15,
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));title
Sometimes it's convenient to change a field's title. This is the purpose of the ui:title uiSchema directive:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = { type: 'string' };
const uiSchema: UiSchema = {
'ui:widget': 'password',
'ui:title': 'Your password',
};submitButtonOptions
Sometimes it's convenient to change the behavior of the submit button for the form. This is the purpose of the ui:submitButtonOptions uiSchema directive:
You can pass any other prop to the submit button if you want, by default, this library will set the following options / props mentioned below for all submit buttons:
`norender` option
You can set this property to true to remove the submit button completely from the form. Nice option, if the form is just for viewing purposes.
`submitText` option
You can use this option to change the text of the submit button. Set to "Submit" by default.
`props` section
You can pass any other prop to the submit button if you want, via this section.
`disabled` prop
You can use this option to disable the submit button.
`className` prop
You can use this option to specify a class name for the submit button.
import { UiSchema } from '@rjsf/utils';
const uiSchema: UiSchema = {
'ui:submitButtonOptions': {
props: {
disabled: false,
className: 'btn btn-info',
},
norender: false,
submitText: 'Submit',
},
};`duplicateKeySuffixSeparator` option
When using additionalProperties, key collision is prevented by appending a unique integer suffix to the duplicate key.
For example, when you add a key named myKey to a form where myKey is already defined, then your new key will become myKey-1.
You can use ui:duplicateKeySuffixSeparator to override the default separator, "-" with a string of your choice on a per-field basis.
You can also set this in the ui:globalOptions to have the same separator used everywhere.
import { UiSchema } from '@rjsf/utils';
const uiSchema = {
'ui:globalOptions': {
duplicateKeySuffixSeparator: '_',
},
};Using uiSchema with oneOf, anyOf
anyOf
The uiSchema will work with elements inside an anyOf as long as the uiSchema defines the anyOf key at the same level as the anyOf within the schema.
Because the anyOf in the schema is an array, so must be the one in the uiSchema.
If you want to override the titles of the first two elements within the anyOf list you would do the following:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = {
type: 'object',
anyOf: [
{
title: 'Strings',
type: 'string',
},
{
title: 'Numbers',
type: 'number',
},
{
title: 'Booleans',
type: 'boolean',
},
],
};
const uiSchema: UiSchema = {
anyOf: [
{
'ui:title': 'Custom String Title',
},
{
'ui:title': 'Custom Number Title',
},
],
};NOTE: Because the third element in the
schemadoes not have an associated element in theuiSchema, it will keep its original title.
oneOf
The uiSchema will work with elements inside an oneOf as long as the uiSchema defines the oneOf key at the same level as the oneOf within the schema.
Because the oneOf in the schema is an array, so must be the one in the uiSchema.
If you want to override the titles of the first two elements within the oneOf list you would do the following:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
const schema: RJSFSchema = {
type: 'object',
oneOf: [
{
title: 'Strings',
type: 'string',
},
{
title: 'Numbers',
type: 'number',
},
{
title: 'Booleans',
type: 'boolean',
},
],
};
const uiSchema: UiSchema = {
oneOf: [
{
'ui:title': 'Custom String Title',
},
{
'ui:title': 'Custom Number Title',
},
],
};NOTE: Because the third element in the
schemadoes not have an associated element in theuiSchema, it will keep its original title.
Theme Options
- AntD Customization
- Chakra-UI Customization
- MUI Customization
- PrimeReact Customization
- Semantic-UI Customization
Packages Docs Docs Api Reference Utility Functions (`packages/docs/docs/api-reference/utility-functions.md`)
RJSF utility functions, constants and types
In version 5, the utility functions from @rjsf/core/utils were refactored into their own library called @rjsf/utils.
These utility functions are separated into two distinct groups.
The first, larger, group are the functions that do NOT require a ValidatorType interface be provided as one of their parameters.
The second, smaller, group are the functions that DO require a ValidatorType interface be provided as a parameter.
There is also a helper function used to create a SchemaUtilsType implementation from a ValidatorType implementation and rootSchema object.
Constants
The @rjsf/utils package exports a set of constants that represent all the keys into various elements of a RJSFSchema or UiSchema that are used by the various utility functions.
In addition to those keys, there is the special ADDITIONAL_PROPERTY_FLAG flag that is added to a schema under certain conditions by the retrieveSchema() utility.
These constants can be found on GitHub here.
Types
Additionally, the Typescript types used by the utility functions represent nearly all the types used by RJSF.
Those types are exported for use by @rjsf/core and all the themes, as well as any customizations you may build.
These types can be found on GitHub here.
ObjectPath — Used by the path utilities (getByPath, setByPath, hasByPath, unsetByPath) to address a value inside a plain object. It is string | number | FieldPathList. A bare string is always a single literal key: 'a.b' means the key 'a.b', never the nested path a → b. To walk a dotted path string, split it explicitly with toPath() first, or pass a FieldPathList ((string | number)[]) of segments. Reads and existence checks resolve own properties only, so inherited members never appear as form data.
SchemaFieldPath — Used when navigating a JSON Schema subtree (for example with getFromSchema and findFieldInSchema on SchemaUtilsType, documented under Validator-based utility functions). It is string | FieldPathList: either a dotted path or an array of segments with the same rules as FieldPathList ((string | number)[]). A numeric segment denotes an array index or an object key that is numeric. Navigation skips only undefined or empty-string segments, so segment 0 is always honored (this avoids the bug from treating 0 as a falsy path unit).
Enums
There are enumerations in @rjsf/utils that are exported for use by @rjsf/core and all the themes, as well as any customizations you may build.
These enums can be found on GitHub here.
Non-Validator utility functions
allowAdditionalItems()
Checks the schema to see if it is allowing additional items, by verifying that schema.additionalItems is an object.
The user is warned in the console if schema.additionalItems has the value true.
Parameters
- schema: S - The schema object to check
Returns
- boolean: True if additional items is allowed, otherwise false
ariaDescribedByIds()
Return a list of element ids that contain additional information about the field that can be used to as the aria description of the field.
Parameters
- id: FieldPathId | string - Either simple string id or an FieldPathId from which to extract it
- [includeExamples=false]: boolean - Optional flag, if true, will add the
examplesIdinto the list
Returns
- string: The string containing the list of ids for use in an
aria-describedByattribute
asNumber()
Attempts to convert the string into a number. If an empty string is provided, then undefined is returned.
If a null is provided, it is returned.
If the string ends in a . then the string is returned because the user may be in the middle of typing a float number.
If a number ends in a pattern like .0, .20, .030, string is returned because the user may be typing number that will end in a non-zero digit.
Otherwise, the string is wrapped by Number() and if that result is not NaN, that number will be returned, otherwise the string value will be.
Parameters
- value: string | null - The string or null value to convert to a number
Returns
- undefined | null | string | number: The
valueconverted to a number when appropriate, otherwise thevalue
bracketNameGenerator()
Generates bracketed names for form fields.
Parameters
- path: FieldPathList - The path of field path units to use when generating the name
- idPrefix: string - The prefix to use at the start of the generated name
- [isMultiValue]: boolean | undefined - Optional flag, if true, will append
[]to the end of the name for multi-value fields (e.g., checkboxes, multi-select)
Returns
- string: The generated bracketed name (e.g.,
root[tasks][0][title], orroot[hobbies][]for multi-value fields)
buttonId()
Return a consistent id for the btn button element
Parameters
- id: FieldPathId | string - The id of the parent component for the option
- btn: 'add' | 'copy' | 'moveDown' | 'moveUp' | 'remove' - The button type for which to generate the id
Returns
- string: The consistent id for the button from the given
idandbtntype
canExpand<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Checks whether the field described by schema, having the uiSchema and formData supports expanding.
The UI for the field can expand if it has additional properties, is not forced as non-expandable by the uiSchema and the formData object doesn't already have schema.maxProperties elements.
Parameters
- schema: S - The schema for the field that is being checked
- [uiSchema={}]: UiSchema<T, S, F> - The uiSchema for the field
- [formData]: T | undefined - The formData for the field
Returns
- boolean: True if the schema element has additionalProperties or patternProperties keywords, is expandable, and not at the maxProperties limit
createErrorHandler<T = any>()
Given a formData object, recursively creates a FormValidation error handling structure around it
Parameters
- formData: T - The form data around which the error handler is created
Returns
- FormValidation<T>: A
FormValidationobject based on theformDatastructure
dataURItoBlob()
Given the FileReader.readAsDataURL() based dataURI extracts that data into an actual Blob along with the name
of that Blob if provided in the URL. If no name is provided, then the name falls back to unknown.
Parameters
- dataURI: string - The
DataUrlpotentially containing name and raw data to be converted to a Blob
Returns
- { blob: Blob, name: string }: An object containing a Blob and its name, extracted from the URI
dateRangeOptions<S extends StrictRJSFSchema = RJSFSchema>()
Returns a list of options for a date range between start and stop.
If the start date is greater than the end date, then the date range is reversed.
If start and stop are negative numbers (or zero), then they will be treated as relative to the current year.
Parameters
- start: number - The starting point of the date range
- stop: number - The ending point of the date range
Returns
- EnumOptionsType<S>[]: The list of EnumOptionsType for the date range between
startandstop
Throws
- Error when
startandstoparen't both %lt;= 0 or > 0
deepEquals()
Implements a deep equals that treats all functions as equivalent and tracks circular references, so self-referential inputs do not recurse infinitely.
Parameters
- a: any - The first element to compare
- b: any - The second element to compare
Returns
- boolean: True if the
aandbare deeply equal, false otherwise
descriptionId()
Return a consistent id for the field description element.
Parameters
- id: FieldPathId | string - Either simple string id or an FieldPathId from which to extract it
Returns
- string: The consistent id for the field description element from the given
id
dotNotationNameGenerator()
Generates dot-notation names for form fields. Multi-value fields are handled the same as single-value fields in dot notation.
Parameters
- path: FieldPathList - The path of field path units to use when generating the name
- idPrefix: string - The prefix to use at the start of the generated name
- [_isMultiValue]: boolean | undefined - Optional flag (unused in dot notation)
Returns
- string: The generated dot-notation name (e.g.,
root.tasks.0.title)
englishStringTranslator()
Translates a TranslatableString value stringToTranslate into english.
When a params array is provided, each value in the array is used to replace any of the replaceable parameters in the stringToTranslate using the %1, %2, etc. replacement specifiers.
Parameters
stringToTranslate: TranslatableString - The TranslatableString value to convert to english
[params]: string[] - The optional list of replaceable parameter values to substitute to the english string
Returns
- string: The
stringToTranslateitself with any replaceable parameter values substituted
enumOptionsDeselectValue<S extends StrictRJSFSchema = RJSFSchema>()
Removes the enum option value at the valueIndex from the currently selected (list of) value(s).
If selected is a list, then that list is updated to remove the enum option value with the valueIndex in allEnumOptions.
If it is a single value, then if the enum option value with the valueIndex in allEnumOptions matches selected, undefined is returned, otherwise the selected value is returned.
Parameters
- valueIndex: string | number - The index of the value to be removed from the selected list or single value
- [selected]: EnumOptionsType<S>["value"] | EnumOptionsType<S>["value"][] | undefined - The current (list of) selected value(s)
- [allEnumOptions=[]]: EnumOptionsType<S>[] - The list of all the known enumOptions
Returns
- EnumOptionsType<S>["value"][]: The updated
selectedlist with thevalueremoved from it
enumOptionSelectedValue<S extends StrictRJSFSchema = RJSFSchema>()
Computes the value to pass to a select element's value attribute.
When format is 'realValue', converts form data values to strings.
When format is 'indexed' (the default), resolves to index-based values via enumOptionsIndexForValue.
Returns emptyValue when the current value is empty.
Parameters
- value: any - The current form data value
- enumOptions: EnumOptionsType<S>[] | undefined - The available enum options
- multiple: boolean - Whether the select allows multiple selections
- [format='indexed']: OptionValueFormat - How option values are encoded on the DOM
- emptyValue: any - The value to return when the selection is empty
Returns
- any: The value to use for the select element's
valueattribute
enumOptionsIndexForValue<S extends StrictRJSFSchema = RJSFSchema>()
Returns the index(es) of the options in allEnumOptions whose value(s) match the ones in value.
All the enumOptions are filtered based on whether they are a "selected" value and the index of each selected one is then stored in an array.
If multiple is true, that array is returned, otherwise the first element in the array is returned.
Parameters
- value: EnumOptionsType<S>["value"] | EnumOptionsType<S>["value"][] - The single value or list of values for which indexes are desired
- [allEnumOptions=[]]: EnumOptionsType<S>[] - The list of all the known enumOptions
- [multiple=false]: boolean - Optional flag, if true will return a list of index, otherwise a single one
Returns
- string | string[] | undefined: A single string index for the first
valueinallEnumOptions, if notmultiple. Otherwise, the list of indexes for (each of) the value(s) invalue.
enumOptionsIsSelected<S extends StrictRJSFSchema = RJSFSchema>()
Determines whether the given value is (one of) the selected value(s).
Parameters
- value: EnumOptionsType<S>["value"] - The value being checked to see if it is selected
- selected: EnumOptionsType<S>["value"] | EnumOptionsType<S>["value"][] - The current selected value or list of values
- [allEnumOptions=[]]: EnumOptionsType<S>[] - The list of all the known enumOptions
Returns
- boolean: true if the
valueis one of theselectedones, false otherwise
enumOptionsSelectValue<S extends StrictRJSFSchema = RJSFSchema>()
Add the value to the list of selected values in the proper order as defined by allEnumOptions.
Parameters
- valueIndex: string | number - The index of the value that should be selected
- selected: EnumOptionsType<S>["value"][] - The current list of selected values
- [allEnumOptions=[]]: EnumOptionsType<S>[] - The list of all the known enumOptions
Returns
- EnumOptionsType<S>["value"][]: The updated list of selected enum values with
valueadded to it in the proper location
enumOptionsValueForIndex<S extends StrictRJSFSchema = RJSFSchema>()
Returns the value(s) from allEnumOptions at the index(es) provided by valueIndex.
If valueIndex is not an array AND the index is not valid for allEnumOptions, emptyValue is returned.
If valueIndex is an array, AND it contains an invalid index, the returned array will have the resulting undefined values filtered out, leaving only valid values or in the worst case, an empty array.
Parameters
- valueIndex: string | number | Array<string | number> - The index(es) of the value(s) that should be returned
- [allEnumOptions=[]]: EnumOptionsType<S>[] - The list of all the known enumOptions
- [emptyValue]: EnumOptionsType<S>["value"] | undefined - The value to return when the non-array
valueIndexdoes not refer to a real option
Returns
- EnumOptionsType<S>["value"] | EnumOptionsType<S>["value"][] | undefined: The single or list of values specified by the single or list of indexes if they are valid. Otherwise,
emptyValueor an empty list.
enumOptionValueDecoder<S extends StrictRJSFSchema = RJSFSchema>()
Decodes a string from a DOM value attribute back to a typed enum value.
When format is 'realValue', does a reverse lookup: finds the enum option whose String(value) matches the input string and returns the original typed value.
For object/array values that were encoded as indices, falls back to index resolution.
When format is 'indexed' (the default), uses index-based resolution via enumOptionsValueForIndex.
Parameters
- value: string | string[] - The string value(s) from the DOM
- enumOptions: EnumOptionsType<S>[] | undefined - The available enum options
- [format='indexed']: OptionValueFormat - How the values were encoded on the DOM
- emptyValue: unknown - The value to return for empty/missing selections
Returns
- unknown: The original typed enum value(s)
enumOptionValueEncoder()
Encodes an enum option value into a string for a DOM value attribute.
When format is 'realValue', primitive values are converted via String().
Non-primitive values (objects, arrays) fall back to the index since String() would produce "[object Object]".
When format is 'indexed' (the default), returns the index as a string.
Parameters
- value: unknown - The typed enum value
- index: number - The option's position in the enumOptions array
- [format='indexed']: OptionValueFormat - How to encode the value for the DOM attribute
Returns
- string: The string to use as the DOM value attribute
logUnsupportedDefaultForEnum<S extends StrictRJSFSchema = RJSFSchema>()
Logs a warning when a single-select enum widget has a schema default that is not one of its enum options.
Multi-select widgets are ignored because they do not use the same single-value default handling.
Parameters
- id: string - The field id used in the warning message
- schema: S - The schema whose default value is checked
- [enumOptions]: EnumOptionsType<S>[] - The enum options available to the widget
- [multiple=false]: boolean - Whether the widget allows multiple selections
errorId()
Return a consistent id for the field error element.
Parameters
- id: FieldPathId | string - Either simple string id or an FieldPathId from which to extract it
Returns
- string: The consistent id for the field error element from the given
id
examplesId()
Return a consistent id for the field examples element.
Parameters
- id: FieldPathId | string - Either simple string id or an FieldPathId from which to extract it
Returns
- string: The consistent id for the field examples element from the given
id
findSchemaDefinition<S extends StrictRJSFSchema = RJSFSchema>()
Given the name of a $ref from within a schema, using the rootSchema, look up and return the sub-schema using the path provided by that reference.
If # is not the first character of the reference, or the path does not exist in the schema, then throw an Error.
Otherwise, return the sub-schema. Also deals with nested $refs in the sub-schema.
Parameters
- $ref: string - The ref string for which the schema definition is desired
- [rootSchema={}]: S - The root schema in which to search for the definition
Returns
- S: The sub-schema within the
rootSchemawhich matches the$refif it exists
Throws
- Error indicating that no schema for that reference exists
getByPath<R = unknown>()
Gets the value at path of obj, returning defaultValue when the resolved value is undefined.
A bare string path is a single literal key, not a dotted path; use toPath() to split a dotted path string into segments first.
Every segment must be an own property, matching hasByPath(), so the two can be used as a guard/read pair.
Inherited members are never resolved: getByPath({}, 'toString') returns defaultValue rather than Function.prototype.toString. For the plain form data and schemas RJSF navigates, an inherited member is never data, and the own-property rule also makes prototype internals such as __proto__ unreachable unless they are genuine own data keys.
An empty segment list resolves to nothing, so defaultValue is returned rather than obj itself; this matches hasByPath(), which is false for an empty path.
The value at a runtime-computed path cannot be known statically, so R is the caller's declaration of the expected type (like Map.get()); it defaults to unknown, which forces narrowing when no type is given.
Parameters
- obj: unknown - The object to query
- path: ObjectPath - The single key or list of path segments at which to get the value
- [defaultValue]: R - The value returned when the resolved value is
undefined
Returns
- R: The resolved value, otherwise
defaultValue
Example
getByPath({ a: { b: 1 } }, ['a', 'b']); // 1
getByPath({ 'a.b': 1 }, 'a.b'); // 1, a bare string is one literal key
getByPath({ a: { b: 1 } }, toPath('a.b')); // 1
getByPath({ a: {} }, ['a', 'missing'], 'fallback'); // 'fallback'
getByPath({}, 'toString', 'fallback'); // 'fallback', inherited members are not read
getByPath({ a: 1 }, [], 'fallback'); // 'fallback', an empty path resolves to nothinggetChangedFields(a: unknown, b: unknown, deep?: boolean)
Compares two objects and returns the names of the fields that have changed.
This function iterates over each field of object a, using _.isEqual to compare the field value with the corresponding field value in object b.
If the values are different, the field name will be included in the returned array.
When deep is true, a field holding a nested object or a same-length array is descended into and the dotted path of the deepest field that changed is returned instead of the name of the top-level field holding it.
A key that contains a . or a [ is descended into like any other: the path it produces cannot be told apart from a path through nested keys, and neither can the entry an ErrorSchema keeps for it, since toErrorSchema() spells such a name out as a path in the same way.
Parameters
- a: unknown - The first object, representing the original data to compare.
- b: unknown - The second object, representing the updated data to compare.
- [deep=false]: boolean - Optional flag that, when true, returns the dotted path of the deepest field that changed.
Returns
- string[] : An array of field names that have changed.
Example
const a = { name: 'John', age: 30 };
const b = { name: 'John', age: 31 };
const changedFields = getChangedFields(a, b);
console.log(changedFields); // Output: ['age']Example (deep)
const a = { items: [{ qux: '', corge: '' }] };
const b = { items: [{ qux: 'a', corge: '' }] };
console.log(getChangedFields(a, b)); // Output: ['items']
console.log(getChangedFields(a, b, true)); // Output: ['items.0.qux']getDecimalSeparator(languages?: string | string[])
Determines the locale-specific decimal separator.
It uses the provided locale or the first locale in navigator.languages (if available) and falls back to "en".
Parameters
- languages?: string | string[] - Optional array of locales or a single locale string.
Returns
- string : The decimal separator character (typically '.' or ',').
Example
const separator = getDecimalSeparator('fr');
console.log(separator); // Output: ','getDiscriminatorFieldFromSchema<S extends StrictRJSFSchema = RJSFSchema>()
Returns the discriminator.propertyName when defined in the schema if it is a string. A warning is generated when it is not a string.
Returns undefined when a valid discriminator is not present.
Parameters
- schema: S - The schema from which the discriminator is potentially obtained
Returns
- string | undefined: The
discriminator.propertyNameif it exists in the schema, otherwiseundefined
getDateElementProps()
Given date & time information with optional yearRange & format, returns props for DateElement
Parameters
- date: DateObject - Object containing date with optional time information
- time: boolean - Determines whether to include time or not
- [yearRange=[1900, new Date().getFullYear() + 2]]: [number, number] - Controls the list of years to be displayed
- [format='YMD']: DateElementFormat - Controls the order in which day, month and year input element will be displayed
Returns
- Array of props for DateElement
getInputProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Using the schema, defaultType and options, extract out the props for the `` element that make sense.
Parameters
- schema: S - The schema for the field provided by the widget
- [defaultType]: string | undefined - The default type, if any, for the field provided by the widget
- [options={}]: UIOptionsType<T, S, F> - The UI Options for the field provided by the widget
- [autoDefaultStepAny=true]: boolean - Determines whether to auto-default step=any when the type is number and no step
Returns
- InputPropsType: The extracted
InputPropsTypeobject
getOptionMatchingSimpleDiscriminator()
Compares the value of discriminatorField within formData against the value of discriminatorField within schema for each option. Returns index of first option whose discriminator matches formData. Returns undefined if there is no match.
This function does not work with discriminators of "type": "object" and "type": "array"
Parameters
- [formData]: T | undefined - The current formData, if any, used to figure out a match
- options: S[] - The list of options to find a matching options from
- [discriminatorField]: string | undefined - The optional name of the field within the options object whose value is used to determine which option is selected
Returns
- number | undefined: index of the matched option
getOptionValueFormat()
Resolves the effective optionValueFormat for enum-backed widgets.
Provides a single source of truth for the default DOM encoding format ('indexed') used by SelectWidget, RadioWidget, and CheckboxesWidget.
Widgets should call this helper once and pass the result to enumOptionValueEncoder, enumOptionValueDecoder, and enumOptionSelectedValue rather than reading options.optionValueFormat directly.
Parameters
- [options]: { optionValueFormat?: OptionValueFormat } | undefined - The widget options (typically from the
optionsprop, already resolved fromui:optionsandui:globalOptions)
Returns
- OptionValueFormat: The resolved
OptionValueFormat, defaulting to'indexed'when not set
getPropertySchema<S extends StrictRJSFSchema = RJSFSchema>()
Returns the sub-schema declared for property in the properties of schema, falling back to an empty schema when the schema has no such property.
Callers treat the properties of a schema as schemas of the same type S, which the JSONSchema7 typing of properties cannot express, so this function owns that single assertion rather than repeating it at every lookup.
Parameters
- schema: S | undefined - The schema, if any, from which to read the property sub-schema
- property: string - The name of the property whose sub-schema is desired
Returns
- S: The sub-schema for
property, or an empty schema when it is not declared
getSchemaType()
Gets the type of a given schema.
If the type is not explicitly defined, then an attempt is made to infer it from other elements of the schema as follows:
- schema.const: Returns the
guessType()of that value - schema.enum: Returns
string - schema.properties: Returns
object - schema.additionalProperties: Returns
object - schema.patternProperties: Returns
object - type is an array with a length of 2 and one type is 'null': Returns the other type
Parameters
- schema: S - The schema for which to get the type
Returns
- string | string[] | undefined: The type of the schema
getSubmitButtonOptions<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Extracts any ui:submitButtonOptions from the uiSchema and merges them onto the DEFAULT_OPTIONS
Parameters
- [uiSchema={}]: UiSchema<T, S, F> - the UI Schema from which to extract submit button props
Returns
- UISchemaSubmitButtonOptions: The merging of the
DEFAULT_OPTIONSwith any custom ones
getTemplate<Name extends keyof TemplatesType<T, S, F>, T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Returns the template with the given name from either the uiSchema if it is defined or from the registry
otherwise. NOTE, since ButtonTemplates are not overridden in uiSchema only those in the registry are returned.
Parameters
- name: Name - The name of the template to fetch, restricted to the keys of
TemplatesType - registry: Registry<T, S, F> - The
Registryfrom which to read the template - [uiOptions={}]: UIOptionsType<T, S, F> - The
UIOptionsTypefrom which to read an alternate template
Returns
- TemplatesType<T, S, F>[Name] - The template from either the
uiSchemaorregistryfor thename
getTestIds()
Returns an object of test IDs that can only be used in test mode.
If the function is called in a test environment (NODE_ENV === 'test', this is set by jest) then a Proxy object will be returned.
If a key within the returned object is accessed, if the value already exists the object will return that value, otherwise it will create that key
with a generated uuid value and return the generated ID.
If it is called outside of a test environment, the function will return an empty object, therefore returning undefined for any property within the object and excluding the prop from the rendered output of the component in which it is used.
To use this helper, you will want to generate a separate object for each component to avoid potential overlapping of ID names.
You will also want to export the object for use in tests, because the keys will be generated in the component file, and used in the test file.
Within the component file, add: export const TEST_IDS = getTestIds();
Then pass TEST_IDS.examplePropertyName as the value of the test ID attribute of the intended component.
This will allow you to use TEST_IDS.examplePropertyName within your tests, while keeping the test IDs out of your rendered output.
Returns
- TestIdShape: An object that auto-generates test ids upon request the first time and then returns the same value on subsequent calls
getUiOptions<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Get all passed options from ui:options, and ui:<optionName>, returning them in an object with the ui: stripped off.
Any globalOptions will always be returned, unless they are overridden by options in the uiSchema.
Parameters
- [uiSchema={}]: UiSchema<T, S, F> - The UI Schema from which to get any
ui:xxxoptions - [globalOptions={}]: GlobalUISchemaOptions - The optional Global UI Schema from which to get any fallback
xxxoptions
Returns
- UIOptionsType<T, S, F> An object containing all of the
ui:xxxoptions with theui:stripped off along with allglobalOptions
getWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Given a schema representing a field to render and either the name or actual Widget implementation, returns the
React component that is used to render the widget. If the widget is already a React component, then it is wrapped
with a MergedWidget. Otherwise an attempt is made to look up the widget inside of the registeredWidgets map based
on the schema type and widget name. If no widget component can be found an Error is thrown.
Parameters
- schema: S - The schema for the field
- widget: Widget<T, S, F> | string - Either the name of the widget OR a
Widgetimplementation to use - [registeredWidgets={}]: RegistryWidgetsType<T, S, F> - A registry of widget name to
Widgetimplementation
Returns
- Widget<T, S, F>: The
Widgetcomponent to use
Throws
- An error if there is no
Widgetcomponent that can be returned
hasByPath()
Determines whether obj has an own property at path.
A bare string path is a single literal key, not a dotted path; use toPath() to split a dotted path string into segments first.
Every segment is checked with Object.hasOwn(), so inherited properties report false — hasByPath({}, 'toString') is false. getByPath() applies the same own-property rule, so the two can be used as a guard/read pair.
Parameters
- obj: unknown - The object to query
- path: ObjectPath - The single key or list of path segments to check for
Returns
- boolean: True if the own property exists at
path, otherwise false
Example
hasByPath({ a: { b: undefined } }, ['a', 'b']); // true, the key exists
hasByPath({ a: { b: 1 } }, 'a.b'); // false, there is no key named 'a.b'
hasByPath({}, 'toString'); // false, inherited properties are not own propertieshashObject()
Stringifies an object and returns the hash of the resulting string.
Sorts object fields in consistent order before stringify to prevent different hash ids for the same object.
Parameters
- object: object - The object for which the hash is desired
Returns
- string: The string obtained from the hash of the stringified object
hashString()
Hashes a string using the algorithm based on Java's hashing function.
Parameters
- string: string - The string for which to get the hash
Returns
- string: The resulting hash of the string in hex format
guessType()
Given a specific value attempts to guess the type of a schema element. In the case where we have to implicitly
create a schema, it is useful to know what type to use based on the data we are defining.
Parameters
- value: any - The value from which to guess the type
Returns
- string: The best guess for the object type
hashForSchema<S extends StrictRJSFSchema = RJSFSchema>()
Stringifies the schema and returns the hash of the resulting string.
Parameters
- schema: S - The schema for which the hash is desired
Returns
- string: The string obtained from the hash of the stringified schema
hasWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Detects whether the widget exists for the schema with the associated registryWidgets and returns true if it does, or false if it doesn't.
Parameters
- schema: S - The schema for the field
- widget: Widget<T, S, F> | string - Either the name of the widget OR a
Widgetimplementation to use - [registeredWidgets={}]: RegistryWidgetsType<T, S, F> - A registry of widget name to
Widgetimplementation
Returns
- boolean: True if the widget exists, false otherwise
helpId()
Return a consistent id for the field help element.
Parameters
- id: FieldPathId | string - Either simple string id or an FieldPathId from which to extract it
Returns
- string: The consistent id for the field help element from the given
id
isConstant<S extends StrictRJSFSchema = RJSFSchema>()
This function checks if the given schema matches a single constant value.
This happens when either the schema has an enum array with a single value or there is a const defined.
Parameters
- schema: S - The schema for a field
Returns
- boolean: True if the
schemahas a single constant value, false otherwise
isCustomWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Checks to see if the uiSchema contains the widget field and that the widget is not hidden
Parameters
- uiSchema: UiSchema<T, S, F> - The UI Schema from which to detect if it is customized
Returns
- boolean: True if the
uiSchemadescribes a custom widget, false otherwise
isFixedItems<S extends StrictRJSFSchema = RJSFSchema>()
Detects whether the given schema contains fixed items.
This is the case when schema.items is a non-empty array that only contains objects.
Parameters
- schema: S - The schema in which to check for fixed items
Returns
- boolean: True if there are fixed items in the schema, false otherwise
isFormDataAvailable<T = any>()
Determines whether the given formData represents valid form data, such as a primitive type, an array, or a non-empty object.
Parameters
- formData: T - The data to check
Returns
- boolean: True if
formDatais not undefined, null, a primitive type or an array or an empty object
isObject()
Determines whether a thing is an object for the purposes of RSJF.
In this case, thing is an object if it has the type object but is NOT null, an array or a File.
Parameters
- thing: any - The thing to check to see whether it is an object
Returns
- boolean: True if it is a non-null, non-array, non-File object
isPlainObject()
Determines whether thing is a plain object, i.e. one created by the Object constructor or with a null prototype.
Unlike isObject(), class instances such as Error are not plain objects, which matters when recursively walking a structure whose nested values are expected to be plain data.
Parameters
- thing: unknown - The thing to check to see whether it is a plain object
Returns
- boolean: True if it is a plain object, otherwise false. When true,
thingis narrowed toRecord<string, unknown>
isRootSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Helper to check whether a JSON schema object is the root schema. The schema is a root schema with root properties
key or a root $ref key. If the schemaToCompare has a root oneOf property, the function will
return false. Else if schemaToCompare and rootSchema are the same object or equal, the function will returntrue. Else if the rootSchema has a $ref, it will be resolved using schemaUtils.resolveSchema utility. If the
resolved schema matches the schemaToCompare the function will return true. Otherwise, it will return false.
Parameters
- registry: Registry<T, S, F> - The
Registryused to get therootSchemaandschemaUtils - schemaToCompare: S - The JSON schema object to check. If
schemaToCompareis an root schema, the function will return true.
Returns
- boolean: True if the
uiSchemadescribes a custom widget, false otherwise
isValueEmpty()
Returns true when a form value is considered empty: null, undefined, or '' (empty string), an empty array ([]), or a plain object whose every own value is itself empty (checked recursively). Scalar values such as 0 and false are not considered empty.
Parameters
- value: unknown - The value to check
Returns
- boolean: True if the value is considered empty, false otherwise
labelValue()
Helper function that will return the value to use for a widget label based on hideLabel.
The fallback is used as the return value from the function when hideLabel is true.
Due to the implementation of theme components, it may be necessary to return something other than undefined to cause the theme component to not render a label.
Some themes require may false and others may require an empty string.
Parameters
[label]: string | ReactElement | undefined - The label string or component to render when not hidden
[hideLabel]: boolean| undefined - Flag, if true, will cause the label to be hidden
[fallback]: undefined | false | '' - One of 3 values,
undefined(the default),falseor an empty stringReturns
string | boolean | undefined:
fallbackifhideLabelis true, otherwiselabel
localToUTC()
Converts a local Date string into a UTC date string
Parameters
- dateString: string - The string representation of a date as accepted by the
Date()constructor
Returns
- string | undefined: A UTC date string if
dateStringis truthy, otherwise undefined
lookupFromFormContext<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any, R = unknown>()
Given a React JSON Schema Form registry or formContext object, return the value associated with toLookup.
This might be contained within the lookup map in the formContext.
If no such value exists, return the fallback value.
Parameters
- regOrFc: Registry<T, S, F> | Registry<T, S, F>['formContext'] - The @rjsf registry or form context in which the lookup will occur
- toLookup: string - The name of the field in the lookup map in the form context to get the value for
- [fallback]: R - The fallback value to use if the form context does not contain a value for
toLookup
Returns
- R: The value associated with
toLookupin the form context orfallback
mergeDefaultsWithFormData<T = any>()
Merges the defaults object of type T into the formData of type T
When merging defaults and form data, we want to merge in this specific way:
- objects are deeply merged
- arrays are merged in such a way that:
- when the array is set in form data, only array entries set in form data are deeply merged; additional entries from the defaults are ignored unless
mergeExtraArrayDefaultsis true, in which case the extras are appended onto the end of the form data - when the array is not set in form data, the default is copied over
- when the array is set in form data, only array entries set in form data are deeply merged; additional entries from the defaults are ignored unless
- scalars are overwritten/set by form data
Parameters
- [defaults]: T | undefined - The defaults to merge
- [formData]: T | undefined - The form data into which the defaults will be merged
- [mergeExtraArrayDefaults=false]: boolean - If true, any additional default array entries are appended onto the formData
- [defaultSupercedesUndefined=false]: boolean - If true, an explicit undefined value will be overwritten by the default value
Returns
- T | undefined: The resulting merged form data with defaults
mergeObjects()
Recursively merge deeply nested objects.
Parameters
- obj1: GenericObjectType - The first object to merge
- obj2: GenericObjectType - The second object to merge
- [concatArrays=false]: boolean | "preventDuplicates" - Optional flag that, when true, will cause arrays to be concatenated. Use "preventDuplicates" to merge arrays in a manner that prevents any duplicate entries from being merged.
Returns
@returns - A new object that is the merge of the two given objects
mergeSchemas()
Recursively merge deeply nested schemas.
The difference between mergeSchemas and mergeObjects is that mergeSchemas only concats arrays for values under the 'required' keyword, and when it does, it doesn't include duplicate values. NOTE: Uses shallow comparison for the duplicate checking.
Parameters
- obj1: GenericObjectType - The first object to merge
- obj2: GenericObjectType - The second object to merge
Returns
- GenericObjectType: The merged schema object
optionalControlsId()
Return a consistent id for the optional data controls element
Parameters
- id: string - The id of the parent component for the option
- element: 'Add' | 'Msg' | 'Remove' - The element type for which to generate the id
Returns
- string: The consistent id for the optional data controls element from the given
idandelementtype
optionId()
Return a consistent id for the optionIndexs of a Radio or Checkboxes widget
Parameters
- id: string - The id of the parent component for the option
- optionIndex: number - The index of the option for which the id is desired
Returns
- string: An id for the option index based on the parent
id
noop()
A function that does nothing and returns undefined, useful as a placeholder for an optional callback or as the implementation of a mocked function.
Returns
- void
optionsList<T = any, S extends StrictRJSFSchema = RJSFSchema,F extends FormContextType = any>()
Gets the list of options from the schema. If the schema has an enum list, then those enum values are returned.
The labels for the options will be extracted from ui:enumNames in the uiSchema if provided, otherwise the label will be the same as the value. If ui:enumOrder is provided, the options will be reordered accordingly.
If the schema has a oneOf or anyOf, then the value is the list of either:
- The
constvalues from the schema if present - If the schema has a discriminator and the label using either the
schema.titleor the value. If auiSchemais
provided, and it has theui:enumNamesmatched withenumor it has an associatedoneOforanyOfwith a list of
objects containingui:titlethen the UI schema values will replace the values from the schema.
Parameters
- schema: S - The schema from which to extract the options list
- [uiSchema]: UiSchema<T, S, F> - The optional uiSchema from which to get alternate labels for the options
Returns
- { schema?: S, label: string, value: any }: The list of options from the schema
orderProperties()
Given a list of properties and an order list, returns a list that contains the properties ordered correctly.
If order is not an array, then the untouched properties list is returned.
Otherwise properties is ordered per the order list.
If order contains a '_' then any properties that are not mentioned explicity in order will be places in the location of the _.
Parameters
- properties: string[] - The list of property keys to be ordered
- order: string[] - An array of property keys to be ordered first, with an optional '*' property
Returns
- string[]: A list with the
propertiesordered
Throws
- Error when the properties cannot be ordered correctly
pad()
Returns a string representation of the num that is padded with leading "0"s if necessary
Parameters
- num: number - The number to pad
- width: number - The width of the string at which no lead padding is necessary
Returns
- string: The number converted to a string with leading zero padding if the number of digits is less than
width
parseDateString()
Parses the dateString into a DateObject, including the time information when includeTime is true
Parameters
- dateString: string - The date string to parse into a DateObject
- [includeTime=true]: boolean - Optional flag, if false, will not include the time data into the object
Returns
- DateObject: The date string converted to a
DateObject
Throws
- Error when the date cannot be parsed from the string
rangeSpec<S extends StrictRJSFSchema = RJSFSchema>()
Extracts the range spec information { step?: number, min?: number, max?: number } that can be spread onto an HTML input from the range analog in the schema { multipleOf?: number, minimum?: number, maximum?: number }.
Parameters
- schema: S - The schema from which to extract the range spec
Returns
- RangeSpecType: A range specification from the schema
replaceStringParameters()
Potentially substitutes all replaceable parameters with the associated value(s) from the params if available.
When a params array is provided, each value in the array is used to replace any of the replaceable parameters in the inputString using the %1, %2, etc. replacement specifiers.
Parameters
- inputString: string - The string which will be potentially updated with replacement parameters
- [params]: string[] - The optional list of replaceable parameter values to substitute into the english string
Returns
- string: The updated string with any replacement specifiers replaced
resolveDefaultWidget<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Computes the widget name a field falls back to when no ui:widget is specified, along with the enumOptions (if any) that back a select-like fallback.
The default is select when schema has enumerable options, the schema's format when a widget is registered for it, or text otherwise.
Parameters
- schema: S - The schema for the field
- uiSchema: UiSchema<T, S, F> | undefined - The uiSchema for the field
- schemaUtils: SchemaUtilsType<T, S, F> - The
SchemaUtilsTypeused to detect whetherschemahas enumerable options - [registeredWidgets={}]: RegistryWidgetsType<T, S, F> - A registry of widget name to
Widgetimplementation
Returns
- { defaultWidget: string, enumOptions: EnumOptionsType<S>[] | undefined }: The default widget name and the
enumOptions, if any, computed along the way
resolveUiSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Resolves the uiSchema for a given schema, considering ui:definitions stored in the registry.
Called at runtime for each field. When the schema contains a $ref, looks up the corresponding uiSchema definition from registry.uiSchemaDefinitions and merges it with local overrides.
For schemas with oneOf/anyOf branches, also populates uiSchema[keyword][i] for branches whose $ref matches a definition, so MultiSchemaField can read dropdown option titles.
Resolution order (later sources override earlier):
ui:definitions[$ref]- base definition from registrylocalUiSchema- local overrides at current path
Parameters
- schema: S - The JSON schema (may contain
$reforRJSF_REF_KEY) - localUiSchema: UiSchema<T, S, F> | undefined - The uiSchema at the current path (local overrides)
- registry: Registry<T, S, F> - The registry containing
uiSchemaDefinitions
Returns
- UiSchema<T, S, F>: The resolved uiSchema with definitions merged in
schemaHasNestedConditional<S extends StrictRJSFSchema = RJSFSchema>()
Recursively checks whether the given raw schema contains a dependencies or if keyword anywhere below its top level, e.g. inside a nested object's properties, a $ref, an array's tuple items, or a patternProperties entry.retrieveSchema() only resolves the dependencies/if declared directly on the schema it is given, so a root-level retrieved schema never reflects a conditional branch switch that happens deeper in the tree.Form uses this to detect when a comparison of root-level retrieved schemas can't be trusted to decide whether sanitization is needed.
Parameters
- schema: S | boolean | undefined - The raw schema node to search
- rootSchema: S - The root schema, used to resolve any
$refs encountered while searching - atRoot: boolean = true - Whether
schemais the root of the search, whose owndependencies/ifdon't count - seenRefs: string[] = [] - The
$refs already resolved along this branch of the search, to guard against cycles
Returns
- boolean: True if a
dependenciesorifkeyword exists below the root of the schema
schemaRequiresTrueValue<S extends StrictRJSFSchema = RJSFSchema>()
Check to see if a schema specifies that a value must be true. This happens when:
schema.constis truthyschema.enum==[true]schema.anyOforschema.oneOfhas a single value which recursively returns trueschema.allOfhas at least one value which recursively returns true
Parameters
- schema: S - The schema to check
Returns
- boolean: True if the schema specifies a value that must be true, false otherwise
setByPath<O>()
Sets value at path of obj, mutating and returning obj.
A bare string path is a single literal key, not a dotted path; use toPath() to split a dotted path string into segments first.
Missing intermediate containers are created: arrays when the next segment is a valid array index, plain objects otherwise, or always plain objects when createIntermediateObjects is true.
A path containing a __proto__ segment is refused and obj is returned unmodified, preventing prototype pollution. constructor and prototype are legal JSON Schema property names and are written normally: intermediate containers are read as own properties only, so ['constructor', 'prototype', 'x'] shadows constructor with a fresh object instead of reaching Object.prototype.
Parameters
- obj: O - The object to modify
- path: ObjectPath - The single key or list of path segments at which to set the value
- value: unknown - The value to set
- [createIntermediateObjects=false]: boolean - When true, always create plain objects for missing intermediate containers, even for numeric path segments
Returns
- O: The mutated
obj
Example
setByPath({}, ['a', 'b'], 1); // { a: { b: 1 } }
setByPath({}, ['a', 0], 1); // { a: [1] }, a numeric next segment creates an array
setByPath({}, ['a', 0], 1, true); // { a: { 0: 1 } }, createIntermediateObjects forces an object
setByPath({}, 'a.b', 1); // { 'a.b': 1 }, a bare string is one literal keyshallowEquals()
Implements a shallow equals comparison that uses Object.is() for comparing values.
This function compares objects by checking if all keys and their values are equal using Object.is().
Parameters
- a: any - The first element to compare
- b: any - The second element to compare
Returns
- boolean: True if the
aandbare shallow equal, false otherwise
shouldRender()
Determines whether the given component should be rerendered by comparing its current set of props and state against the next set.
If either of those two sets are not the same, then the component should be rerendered.
Parameters
- component: React.Component - A React component being checked
- nextProps: any - The next set of props against which to check
- nextState: any - The next set of state against which to check
Returns
- True if boolean: the component should be re-rendered, false otherwise
shouldRenderOptionalField<T = any, S extends StrictRJSFSchema = RJSFSchema,F extends FormContextType = any>()
Determines whether the field information from the combination of schema and required along with theenableOptionalDataFieldForType settings from the global UI options in the registry all indicate that this field
should be rendered with the Optional Data Controls UI.
Parameters
- registry: Registry<T, S, F> - The
registryobject - schema: S - The schema for the field
- required - Flag indicating whether the field is required
- [uiSchema]: UiSchema<T, S, F> - The optional uiSchema for the field
Returns
- boolean: True if the field should be rendered with the optional field UI, otherwise false
sortedJSONStringify()
Stringifies an object, sorts object fields in consistent order before stringifying it.
Parameters
- object: object - The object for which the sorted stringify is desired
Returns
- string: The stringified object with keys sorted in a consistent order
titleId()
Return a consistent id for the field title element.
Parameters
- id: FieldPathId | string - Either simple string id or an FieldPathId from which to extract it
Returns
- string: The consistent id for the field title element from the given
id
toConstant<S extends StrictRJSFSchema = RJSFSchema>()
Returns the constant value from the schema when it is either a single value enum or has a const key.
Otherwise, throws an error.
Parameters
- schema: S - The schema from which to obtain the constant value
Returns
- string | number | boolean: The constant value for the schema
Throws
- Error when the schema does not have a constant value
toDateString()
Returns a UTC date string for the given dateObject.
If time is false, then the time portion of the string is removed.
Parameters
- dateObject: DateObject - The
DateObjectto convert to a date string - [time=true]: boolean - Optional flag used to remove the time portion of the date string if false
Returns
- string: The UTC date string
toErrorList<T = any>()
Converts an errorSchema into a list of RJSFValidationErrors
Parameters
- errorSchema: ErrorSchema<T> - The
ErrorSchemainstance to convert - [fieldPath=[]]: string[] | undefined - The current field path, defaults to [] if not specified
Returns
- RJSFValidationErrors[]: The list of
RJSFValidationErrorsextracted from theerrorSchema
toErrorSchema<T = any>()
Transforms a RJSF validation errors list into an ErrorSchema
const changesThis = [
{ property: '.level1.level2[2].level3', message: 'err a', stack: '.level1.level2[2].level3 err a' },
{ property: '.level1.level2[2].level3', message: 'err b', stack: '.level1.level2[2].level3 err b' },
{ property: '.level1.level2[4].level3', message: 'err b', stack: '.level1.level2[4].level3 err b' },
];
const intoThis = {
level1: {
level2: {
2: { level3: { errors: ['err a', 'err b'] } },
4: { level3: { errors: ['err b'] } },
},
},
};Parameters
- errors: RJSFValidationError[] - The list of RJSFValidationError objects
Returns
- ErrorSchema<T>: The
ErrorSchemabuilt from the list ofRJSFValidationErrors
toFieldPathId()
Constructs the FieldPathId for fieldPath. If parentPathId is provided, the fieldPath is appended to the end
of the parent path. Then the ID_KEY of the resulting FieldPathId is constructed from the idPrefix andidSeparator contained within the globalFormOptions. If fieldPath is passed as an empty string, it will simply
generate the path from the parentPath (if provided) and the idPrefix and idSeparator
Parameters
- fieldPath: string | number - The property name or array index of the current field element
- globalFormOptions: GlobalFormOptions - The
GlobalFormOptionsused to get theidPrefixandidSeparator - [parentPath]: FieldPathId | FieldPathList | undefined - The optional
FieldPathIdorFieldPathListof the parent element for this field element
Returns
- FieldPathId: The
FieldPathIdfor the givenfieldPathand the optionalparentPathId
toPath()
Converts a dotted path string, such as the property of a validation error, into its list of path segments.
Array indexes may be written bracketed ('a[0].b') or dotted ('a.0.b'), and empty segments — from a leading ., a trailing . or a .. run — are dropped.
Only the grammar RJSF itself produces is supported: dots and brackets are always separators, so quoted keys are not recognized and keys containing dots must be addressed with a segment list instead of a string.
Parameters
- path: string - The string path to convert, such as
'.level1.level2[2].level3'
Returns
- string[]: The list of path segments, such as
['level1', 'level2', '2', 'level3']
Example
toPath('.level1.level2[2].level3'); // ['level1', 'level2', '2', 'level3']
toPath('a.0.b'); // ['a', '0', 'b']
getByPath(formData, toPath(error.property)); // the usual pairing with the path utilitiesunsetByPath()
Removes the own property at path of obj, mutating obj.
A bare string path is a single literal key, not a dotted path; use toPath() to split a dotted path string into segments first.
Parameters
- obj: unknown - The object to modify
- path: ObjectPath - The single key or list of path segments at which to remove the property
Returns
- boolean: True if the property was removed or did not exist, otherwise false. A non-configurable property returns false rather than throwing in strict mode
Example
const obj = { a: { b: 1 } };
unsetByPath(obj, ['a', 'b']); // true, obj is now { a: {} }
unsetByPath(obj, ['a', 'missing']); // true, nothing to removeunwrapErrorHandler<T = any>()
Unwraps the errorHandler structure into the associated ErrorSchema, stripping the addError() functions from it
Parameters
- errorHandler: FormValidation<T> - The
FormValidationerror handling structure
Returns
- ErrorSchema<T>: The
ErrorSchemaresulting from the stripping of theaddError()function
useAltDateWidgetProps<T = unknown, S extends StrictRJSFSchema = RJSFSchema,F extends FormContextType = any>`()
Hook which encapsulates the logic needed to render an AltDateWidget with optional time elements. It contains
the state of the current date(/time) selections in the widget. It returns a UseAltDateWidgetResult object
that contains the elements: DateElementProp[] and three callbacks needed to change one of the rendered elements,
and to handle the clicking of the clear and setNow buttons.
Parameters
- props: WidgetProps<T, S, F> - The
WidgetPropsfor theAltDateWidget
Returns
- UseAltDateWidgetResult: The
UseAltDateWidgetResultto be used within aAltDateWidgetimplementation
useDeepCompareMemo<T = unknown>()
Hook that stores and returns a T. If newValue is the same as the stored one, then the stored one is returned to
avoid having a component rerender due it being a different object. Otherwise, the newValue is stored and returned.
Parameters
- newValue: T - The potential new
Tvalue
Returns
- T: The latest stored
Tvalue
useFileWidgetProps()
Hook which encapsulates the logic needed to read and convert a value of File or File[] into thefilesInfo: FileInfoType[] and the two callback implementations needed to change the list or to remove aFile from the list. To be used by theme specific FileWidget implementations.
Parameters
- value: string | string[] | undefined | null - The current value of the
FileWidget - onChange: (value: string | null | (string | null)[]) => void - The onChange handler for the
FileWidget - [multiple=false] - Flag indicating whether the control supports multiple selections
Returns
- UseFileWidgetPropsResult: The
UseFileWidgetPropsResultto be used within aFileWidgetimplementation
utcToLocal()
Converts a UTC date string into a local Date format
Parameters
- jsonDate: string - A UTC date string
Returns
- string: An empty string when
jsonDateis falsey, otherwise a date string in local format
validationDataMerge<T = any>()
Merges the errors in additionalErrorSchema into the existing validationData by combining the hierarchies in the two ErrorSchemas and then appending the error list from the additionalErrorSchema obtained by calling toErrorList() on the errors in the validationData.
If no additionalErrorSchema is passed, then validationData is returned.
Parameters
- validationData: ValidationData<T> - The current
ValidationDatainto which to merge the additional errors - [additionalErrorSchema]: ErrorSchema<T> | undefined - The optional additional set of errors in an
ErrorSchema - [preventDuplicates=false]: boolean - Optional flag, if true, will call
mergeObjects()withpreventDuplicates
Returns
- ValidationData<T>: The
validationDatawith the additional errors fromadditionalErrorSchemamerged into it, if provided.
withIdRefPrefix<S extends StrictRJSFSchema = RJSFSchema>()
Recursively prefixes all $refs in a schema with the value of the ROOT_SCHEMA_PREFIX constant.
This is used in isValid to make references to the rootSchema
Parameters
- schemaNode: S - The object node to which a
ROOT_SCHEMA_PREFIXis added when a$refis part of it
Returns
- S: A copy of the
schemaNodewith updated$refs
Validator-based utility functions
findFieldInSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Finds the field at the given path within the root or a nested schema node, following oneOf / anyOf using formData where needed. If nothing matches the path, { field: undefined, isRequired: undefined } is returned. When a leaf is found, the result includes whether that leaf is required under its parent.
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be forwarded to all the APIs - rootSchema: S - The root schema that will be forwarded to all the APIs
- schema: S - The node within the JSON schema in which to search
- path: SchemaFieldPath - Dotted path or segment list to the desired field; see
SchemaFieldPath - [formData={}]: T - The form data that is used to determine which anyOf/oneOf option to descend
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See
Formdocumentation for the experimental_customMergeAllOf prop
Returns
- FoundFieldType<S>: An object that contains the field and its required state. If no field can be found then
{ field: undefined, isRequired: undefined }is returned.
findSelectedOptionInXxxOf<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Finds the option inside the schema['any/oneOf'] list which has the properties[selectorField].default or properties[selectorField].const that matches the formData[selectorField] value.
For the purposes of this function, selectorField is either schema.discriminator.propertyName or fallbackField.
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be forwarded to all the APIs - rootSchema: S | undefined - The root schema that will be forwarded to all the APIs
- schema: S - The schema element in which to search for the selected anyOf/oneOf option
- fallbackField: string - The field to use as a backup selector field if the schema does not have a required field
- xxx: 'anyOf' | 'oneOf' - Either
anyOforoneOf, defines which value is being sought - [formData={}]: T - The form data that is used to determine which anyOf/oneOf option to descend
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See
Formdocumentation for the experimental_customMergeAllOf prop
Returns
- S | undefined: The anyOf/oneOf option that matches the selector field in the schema or undefined if nothing is selected
getDefaultFormState<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Returns the superset of formData that includes the given set updated to include any missing fields that have computed to have defaults provided in the schema.
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be used when necessary - theSchema: S - The schema for which the default state is desired
- [formData]: T | undefined - The current formData, if any, onto which to provide any missing defaults
- [rootSchema]: S | undefined - The root schema, used to primarily to look up
$refs - [includeUndefinedValues=false]: boolean | "excludeObjectChildren" - Optional flag, if true, cause undefined values to be added as defaults. If "excludeObjectChildren", cause undefined values for this object and pass
includeUndefinedValuesas false when computing defaults for any nested object properties. - [experimental_defaultFormStateBehavior]: Experimental_DefaultFormStateBehavior - See
Formdocumentation for the experimental_defaultFormStateBehavior prop - [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See
Formdocumentation for the experimental_customMergeAllOf prop - [initialDefaultsGenerated]: boolean - Optional flag, indicates whether or not initial defaults have been generated
Returns
- T: The resulting
formDatawith all the defaults provided
getDisplayLabel<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Determines whether the combination of schema and uiSchema properties indicates that the label for the schema should be displayed in a UI.
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be used when necessary - schema: S - The schema for which the display label flag is desired
- [uiSchema={}]: UiSchema<T, S, F> - The UI schema from which to derive potentially displayable information
- [rootSchema]: S | undefined - The root schema, used to primarily to look up
$refs - [globalOptions={}]: GlobalUISchemaOptions - The optional Global UI Schema from which to get any fallback
xxxoptions
Returns
- boolean: True if the label should be displayed or false if it should not
getClosestMatchingOption<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Determines which of the given options provided most closely matches the formData.
Returns the index of the option that is valid and is the closest match, or 0 if there is no match.
The closest match is determined using the number of matching properties, and more heavily favors options with matching readOnly, default, or const values.
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be used when necessary - rootSchema: S - The root schema, used to primarily to look up
$refs - [formData]: T | undefined - The current formData, if any, used to figure out a match
- options: S[] - The list of options to find a matching options from
- [selectedOption=-1]: number - The index of the currently selected option, defaulted to -1 if not specified
- [discriminatorField]: string | undefined - The optional name of the field within the options object whose value is used to determine which option is selected
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See
Formdocumentation for the experimental_customMergeAllOf prop
Returns
- number: The index of the option that is the closest match to the
formDataor theselectedOptionif no match
getDisplayLabel<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Determines whether the combination of schema and uiSchema properties indicates that the label for the schema should be displayed in a UI.
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be used when necessary - schema: S - The schema for which the display label flag is desired
- [uiSchema={}]: UiSchema<T, S, F> - The UI schema from which to derive potentially displayable information
- [rootSchema]: S | undefined - The root schema, used to primarily to look up
$refs - [globalOptions={}]: GlobalUISchemaOptions - The optional Global UI Schema from which to get any fallback
xxxoptions - [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See
Formdocumentation for the experimental_customMergeAllOf prop
Returns
- boolean: True if the label should be displayed or false if it should not
getFromSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Reads the value at path within a schema, additionally retrieving $refs as needed to resolve schemas containing potentially nested $refs.
The path accepts a SchemaFieldPath (dotted string or FieldPathList-style segment array).
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be forwarded to all the APIs - rootSchema: S - The root schema that will be forwarded to all the APIs
- schema: S - The current node within the JSON schema recursion
- path: SchemaFieldPath - Dotted path or segment list to the desired field; see
SchemaFieldPath - defaultValue: T | S - The value to return if a value is not found for the
pathListpath - [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See
Formdocumentation for the experimental_customMergeAllOf prop
Returns
- T | S: The inner schema from the
schemafor the givenpathor thedefaultValueif not found
getFirstMatchingOption<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Given the formData and list of options, attempts to find the index of the first option that matches the data.
Always returns the first option if there is nothing that matches.
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be used when necessary - [formData]: T | undefined - The current formData, if any, used to figure out a match
- options: S[] - The list of options to find a matching options from
- rootSchema: S - The root schema, used to primarily to look up
$refs - [discriminatorField]: string | undefined - The optional name of the field within the options object whose value is used to determine which option is selected
Returns
- number: The index of the first matched option or 0 if none is available
isMultiSelect<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Checks to see if the schema combination represents a multi-select
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be used when necessary - schema: S - The schema for which check for a multi-select flag is desired
- [rootSchema]: S | undefined - The root schema, used to primarily to look up
$refs - [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See
Formdocumentation for the experimental_customMergeAllOf prop
Returns
- boolean: True if schema contains a multi-select, otherwise false
isSelect<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Checks to see if the schema combination represents a select
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be used when necessary - theSchema: S - The schema for which check for a select flag is desired
- [rootSchema]: S | undefined - The root schema, used to primarily to look up
$refs - [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See
Formdocumentation for the experimental_customMergeAllOf prop
Returns
- boolean: True if schema contains a select, otherwise false
relaxOptionsForScoring<S extends StrictRJSFSchema = RJSFSchema>()
Normalises a list of oneOf/anyOf options for use in option-scoring only (not for filtering).
Boolean schemas are converted to their object equivalents (true → {}, false → {not:{}}).
When resolveRefs is true, each object option is first passed through resolveAllReferences so that $ref-based options expose their additionalProperties constraint before relaxation.
Any option whose additionalProperties is false is widened to true so that getClosestMatchingOption / validator.isValid() does not produce false negatives when the form data contains keys not listed in properties.
Parameters
- options: Array<S | boolean> - The raw
oneOf/anyOfarray, which may contain boolean schemas - [resolveRefs=false]: boolean - When
true, resolve$refs in each option before relaxing; passrootSchemaas well. Setfalse(default) when refs are already resolved at the call site - [rootSchema]: S | undefined - Required when
resolveRefsistrue; the root schema used to look up$refs
Returns
- S[]: A new array of plain schema objects with
additionalPropertiesrelaxed where needed
removeOptionalEmptyObjects<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
NOTE: This function is deprecated and will be removed in a future release. The equivalent pruning behavior is now built into
omitExtraData— use that instead.
Recursively removes optional objects from the formData that are empty (i.e., all their fields are undefined, null, empty strings, or themselves empty optional objects).
This solves the problem where interacting with fields inside an optional object "activates" it permanently, making the form unsubmittable when the optional object has required inner fields.
An object property is considered "optional" when it is NOT listed in its parent schema's required array.
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be used when necessary - schema: S - The JSON schema describing the
formData - [rootSchema]: S | undefined - The root schema, used primarily to look up
$refs - [formData]: T | undefined - The current form data to prune
Returns
- T | undefined: A new copy of
formDatawith empty optional objects removed, orundefinedif the entire formData was pruned
retrieveSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Retrieves an expanded schema that has had all of its conditions, additional properties, references and dependencies
resolved and merged into the schema given a validator, rootSchema and rawFormData that is used to do the
potentially recursive resolution.
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be forwarded to all the APIs - schema: S - The schema for which retrieving a schema is desired
- [rootSchema={}]: S - The root schema that will be forwarded to all the APIs
- [rawFormData]: T | undefined - The current formData, if any, to assist retrieving a schema
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See
Formdocumentation for the experimental_customMergeAllOf prop
Returns
- RJSFSchema: The schema having its conditions, additional properties, references and dependencies resolved
omitExtraData<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Takes a schema and formData and returns a copy of the formData with any fields not defined in the schema removed.
This is useful for ensuring that only data that is relevant to the schema is preserved.
Objects with additionalProperties keyword set to true will not have their extra fields removed.
const schema = {
type: 'object',
properties: {
child1: {
type: 'object',
properties: {
name: { type: 'string' },
},
},
child2: {
type: 'object',
properties: {
name: { type: 'string' },
},
additionalProperties: true,
},
},
};
const formData = {
child1: {
name: 'John Doe',
extraField: 'This should be removed',
},
child2: {
name: 'Jane Doe',
extraField: 'This should NOT be removed',
},
};
const filteredFormData = omitExtraData(validator, schema, schema, formData);
console.log(filteredFormData);
/*
{
child1: {
name: "John Doe",
},
child2: {
name: "Jane Doe",
extraField: "This should NOT be removed",
},
}
*/Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be used when necessary - schema: S - The schema to use for filtering the formData
- [rootSchema]: S | undefined - The root schema, used to primarily to look up
$refs - [formData]: T | undefined - The formData to filter
Returns
- T: The new form data, with any fields not defined in the schema removed
sanitizeDataForNewSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Sanitize the data associated with the oldSchema so it is considered appropriate for the newSchema.
If the new schema does not contain any properties, then undefined is returned to clear all the form data.
Due to the nature of schemas, this sanitization happens recursively for nested objects of data.
Also, any properties in the old schema that are non-existent in the new schema are set to undefined.
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be used when necessary - rootSchema: S - The root JSON schema of the entire form
- [newSchema]: S | undefined - The new schema for which the data is being sanitized
- [oldSchema]: S | undefined - The old schema from which the data originated
- [data={}]: any - The form data associated with the schema, defaulting to an empty object when undefined
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See
Formdocumentation for the experimental_customMergeAllOf prop
Returns
- T: The new form data, with all the fields uniquely associated with the old schema set to
undefined. Will returnundefinedif the new schema is not an object containing properties.
toPathSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
NOTE: This function is deprecated and will be removed as an exported
@rjsf/utilsfunction in a future release.
Generates an PathSchema object for the schema, recursively
Parameters
- validator: ValidatorType<T, S, F> - An implementation of the
ValidatorTypeinterface that will be used when necessary - schema: S - The schema for which the
PathSchemais desired - [name='']: string - The base name for the schema
- [rootSchema]: S | undefined - The root schema, used to primarily to look up
$refs - [formData]: T | undefined - The current formData, if any, to assist retrieving a schema
- [experimental_customMergeAllOf]: Experimental_CustomMergeAllOf<S> - See
Formdocumentation for the experimental_customMergeAllOf prop
Returns
- PathSchema<T> - The
PathSchemaobject for theschema
Schema utils creation function
createSchemaUtils<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Creates a SchemaUtilsType interface that is based around the given validator and rootSchema parameters.
The resulting interface implementation will forward the validator and rootSchema to all the wrapped APIs.
Parameters
- validator: ValidatorType<T, S, F> - an implementation of the
ValidatorTypeinterface that will be forwarded to all the APIs - rootSchema: S - The root schema that will be forwarded to all the APIs
Returns
- SchemaUtilsType<T, S, F> - An implementation of a
SchemaUtilsTypeinterface
ErrorSchema builder class
ErrorSchemaBuilder<T = any>(initialSchema?: ErrorSchema<T>) constructor
The ErrorSchemaBuilder<T> is used to build an ErrorSchema<T> since the definition of the ErrorSchema type is designed for reading information rather than writing it.
Use this class to add, replace or clear errors in an error schema by using either dotted path or an array of path names.
Once you are done building the ErrorSchema, you can get the result and/or reset all the errors back to an initial set and start again.
Parameters
- [initialSchema]: ErrorSchema<T> | undefined - The optional set of initial errors, that will be cloned into the class
Returns
- ErrorSchemaBuilder<T> - The instance of the
ErrorSchemaBuilderclass
ErrorSchema getter function
Returns the ErrorSchema that has been updated by the methods of the ErrorSchemaBuilder
Usage:
import { ErrorSchemaBuilder, ErrorSchema } from "@rjsf/utils";
const builder = new ErrorSchemaBuilder();
// Do some work using the builder
...
const errorSchema: ErrorSchema = builder.ErrorSchema;resetAllErrors()
Resets all errors in the ErrorSchemaBuilder back to the initialSchema if provided, otherwise an empty set.
Parameters
- [initialSchema]: ErrorSchema<T> | undefined - The optional set of initial errors, that will be cloned into the class
Returns
- ErrorSchemaBuilder<T> - The instance of the
ErrorSchemaBuilderclass
addErrors()
Adds the errorOrList to the list of errors in the ErrorSchema at either the root level or the location within the schema described by the pathOfError.
The path is either a dotted string, with optional bracketed array indexes such as 'level1.level2[2]', or a list of segments; see toPath() for the grammar a string path accepts.
Parameters
- errorOrList: string | string[] - The error or list of errors to add into the
ErrorSchema - [pathOfError]: string | (string | number)[] | undefined - The optional path into the
ErrorSchemaat which to add the error(s)
Returns
- ErrorSchemaBuilder<T> - The instance of the
ErrorSchemaBuilderclass
setErrors()
Sets/replaces the errorOrList as the error(s) in the ErrorSchema at either the root level or the location within the schema described by the pathOfError.
The path is either a dotted string, with optional bracketed array indexes such as 'level1.level2[2]', or a list of segments; see toPath() for the grammar a string path accepts.
Parameters
- errorOrList: string | string[] - The error or list of errors to add into the
ErrorSchema - [pathOfError]: string | (string | number)[] | undefined - The optional path into the
ErrorSchemaat which to add the error(s)
Returns
- ErrorSchemaBuilder<T> - The instance of the
ErrorSchemaBuilderclass
clearErrors()
Clears the error(s) in the ErrorSchema at either the root level or the location within the schema described by the pathOfError.
The path is either a dotted string, with optional bracketed array indexes such as 'level1.level2[2]', or a list of segments; see toPath() for the grammar a string path accepts.
Parameters
- [pathOfError]: string | (string | number)[] | undefined - The optional path into the
ErrorSchemaat which to add the error(s)
Returns
- ErrorSchemaBuilder<T> - The instance of the
ErrorSchemaBuilderclass
Packages Docs Docs Api Reference Validator Ajv8 (`packages/docs/docs/api-reference/validator-ajv8.md`)
@rjsf/validator-ajv8 APIs
In RJSF version 6, the original, embedded AJV 6 validator implementation from earlier versions was removed in favor of the @rjsf/validator-ajv8 package.@rjsf/validator-ajv8 uses the AJV 8 package, including adding support for using precompiled validators.
Below are the exported API functions that are provided by this package.
See the Validation documentation for examples of using these APIs.
Types
There are a few Typescript types that are exported by @rjsf/validator-ajv8 in support of the APIs.
These types can be found on GitHub here.
APIs
customizeValidator<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Creates and returns a customized implementation of the ValidatorType with the given customization options if provided.
If a localizer is provided, it is used to translate the messages generated by the underlying AJV validation.
Parameters
- [options={}]: CustomValidatorOptionsType - The optional map of
CustomValidatorOptionsTypeoptions that are used to create theValidatorTypeinstance. Supported options:additionalMetaSchemas: Additional meta schemas the validator can accesscustomFormats: Additional custom format validatorsajvOptionsOverrides: Config overrides passed to the AJV constructorajvFormatOptions: Options forajv-formats; passfalseto disable format support entirelyAjvClass: The AJV class to construct (e.g.Ajv2019,Ajv2020)extenderFn: A function called to extend the AJV instance (e.g.ajvErrors())suppressDuplicateFiltering: Controls filtering of duplicateanyOf/oneOferrors using theSuppressDuplicateFilteringTypetype.'none'(default) filters duplicates for both;'anyOf'suppresses filtering foranyOf(oneOf duplicates still filtered);'oneOf'suppresses filtering foroneOf(anyOf duplicates still filtered);'all'disables all duplicate filtering.
- [localizer]: Localizer | undefined - If provided, is used to localize a list of Ajv
ErrorObjects after running the form validation using AJV
Returns
- AJV8Validator<T, S, F>: The custom validator implementation resulting from the set of parameters provided
compileSchemaValidators<S extends StrictRJSFSchema = RJSFSchema>()
The function used to compile a schema into an output file in the form that allows it to be used as a precompiled validator.
The main reasons for using a precompiled validator is reducing code size, improving validation speed and, most importantly, avoiding dynamic code compilation when prohibited by a browser's Content Security Policy.
For more information about AJV code compilation see: https://ajv.js.org/standalone.html
Parameters
- schema: S - The schema to be compiled into a set of precompiled validators functions
- output: string - The name of the file into which the precompiled validator functions will be generated
- [options={}]: CustomValidatorOptionsType - The set of
CustomValidatorOptionsTypeinformation used to alter the AJV validator used for compiling the schema. They are the same options that are passed to thecustomizeValidator()function in order to modify the behavior of the regular AJV-based validator.
createPrecompiledValidator<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Creates and returns a ValidatorType interface that is implemented with a precompiled validator.
If a localizer is provided, it is used to translate the messages generated by the underlying AJV validation.
NOTE: The
validateFnsparameter is an object obtained by importing from a precompiled validation file created via thecompileSchemaValidators()function.
Parameters
- validateFns: ValidatorFunctions - The map of the validation functions that are created by the
compileSchemaValidators()function - rootSchema: S - The root schema that was used with the
compileSchemaValidators()function - [localizer]: Localizer | undefined - If provided, is used to localize a list of Ajv
ErrorObjects after running the form validation using AJV - [suppressDuplicateFiltering]:
SuppressDuplicateFilteringType | undefined- Controls filtering of duplicateanyOf/oneOferrors. SeecustomizeValidator()for full description of each value.
Returns
- ValidatorType<T, S, F>: The precompiled validator implementation resulting from the set of parameters provided
Packages Docs Docs Api Reference Validator Ata (`packages/docs/docs/api-reference/validator-ata.md`)
@rjsf/validator-ata APIs
@rjsf/validator-ata is an alternative to @rjsf/validator-ajv8, backed by ata-validator instead of AJV.
The public surface mirrors the AJV package, so swapping the import is enough for the form to keep working: customizeValidator(), ValidatorType<T, S, F>, custom formats, transformErrors, customValidate, and suppressDuplicateFiltering all behave the same.
See the Validation documentation for examples of using these APIs.
Differences from `@rjsf/validator-ajv8`
- AJV-only options (
AjvClass,ajvFormatOptions,ajvOptionsOverrides) are not accepted. The closest equivalent isataOptionsOverrides, which is spread on top of the defaultata-validatoroptions. - The
ata-validatorformat set is always installed, so there is no opt-in flag for formats. ata-validator's error params are frozen, so the pre-quote pass thatvalidator-ajv8runs forajv-i18nis unnecessary. Localizers that mutatemessagein place still work as-is.- Precompiled validators (
compileSchemaValidators/createPrecompiledValidator) are supported.ata-validator'sbundleStandaloneoutput is adapted into the validator function map the precompiled consumer expects. Error output matches the non-precompiled validator, including per-field errors for schema-valuedadditionalProperties(withata-validator>= 0.17.4); an invalidanyOfreports a single error on the field, the same as the runtime path. One constraint carries over from the standalone (AOT) path: custom formats must be a RegExp or pre-anchored string pattern, since a function checker cannot be serialized into the bundle and is rejected at compile time.
Types
There are a few TypeScript types that are exported by @rjsf/validator-ata in support of the APIs. These types can be found on GitHub here.
APIs
customizeValidator<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Creates and returns a customized implementation of the ValidatorType with the given customization options if provided.
If a localizer is provided, it is used to translate the messages generated by the underlying ata-validator validation.
Parameters
- [options={}]: CustomValidatorOptionsType - The optional map of
CustomValidatorOptionsTypeoptions that are used to create theValidatorTypeinstance. Supported options:additionalMetaSchemas: Additional schemas registered for cross-schema$refresolutioncustomFormats: Custom format checkers; values can be functions, RegExps, or pre-anchored regex source stringsataOptionsOverrides: Overrides spread on top of the defaultata-validatoroptions (e.g.coerceTypes,removeAdditional,verbose,abortEarly)extenderFn: A function called against the constructedValidatorinstance for additional setup; returning a different instance is supportedsuppressDuplicateFiltering: Controls filtering of duplicateanyOf/oneOferrors using theSuppressDuplicateFilteringTypetype.'none'(default) filters duplicates for both;'anyOf'suppresses filtering foranyOf(oneOf duplicates still filtered);'oneOf'suppresses filtering foroneOf(anyOf duplicates still filtered);'all'disables all duplicate filtering.
- [localizer]: Localizer | undefined - If provided, is used to localize a list of
ata-validatorValidationErrors after running the form validation
Returns
- ValidatorType<T, S, F>: The custom validator implementation resulting from the set of parameters provided
compileSchemaValidators<S extends StrictRJSFSchema = RJSFSchema>()
Compiles a schema into an output file that can be loaded later as a precompiled validator.
The main reasons for using a precompiled validator are reducing code size, improving startup time by skipping schema compilation, and avoiding dynamic code generation when a browser's Content Security Policy forbids it.
Under the hood this calls ata-validator's bundleStandalone and wraps the result in the map the precompiled consumer expects.
NOTE: Custom formats passed through
options.customFormatsmust be a RegExp or a pre-anchored string pattern. A function checker cannot be serialized into the standalone bundle and is rejected at compile time.
Parameters
- schema: S - The schema to be compiled into a set of precompiled validator functions
- output: string - The name of the file into which the precompiled validator functions are generated
- [options={}]: CustomValidatorOptionsType - The
CustomValidatorOptionsTypeoptions accepted bycustomizeValidator(), with limits:extenderFn, extra schemas without an$idand theataOptionsOverrideskeyscoerceTypes,removeAdditionalandkeywordscannot be carried into the generated file and are ignored with a warning, the generated file never fills indefaultvalues, andsuppressDuplicateFilteringbelongs tocreatePrecompiledValidator(). See the precompiled section ofusage/validation.md
createPrecompiledValidator<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>()
Creates and returns a ValidatorType interface that is implemented with a precompiled validator.
If a localizer is provided, it is used to translate the messages generated by the underlying ata-validator validation.
NOTE: The
validateFnsparameter is an object obtained by importing from a precompiled validation file created via thecompileSchemaValidators()function.
Parameters
- validateFns: ValidatorFunctions - The map of the validation functions that are created by the
compileSchemaValidators()function - rootSchema: S - The root schema that was used with the
compileSchemaValidators()function - [localizer]: Localizer | undefined - If provided, is used to localize the list of
ata-validatorValidationErrors after running the form validation - [suppressDuplicateFiltering]:
SuppressDuplicateFilteringType | undefined- Controls filtering of duplicateanyOf/oneOferrors. SeecustomizeValidator()for the full description of each value.
Returns
- ValidatorType<T, S, F>: The precompiled validator implementation resulting from the set of parameters provided
Packages Docs Docs Api Reference Validator Cfworker (`packages/docs/docs/api-reference/validator-cfworker.md`)
@rjsf/validator-cfworker APIs
@rjsf/validator-cfworker is an additional, eval-free validator option for CSP-constrained applications. It is backed by @cfworker/json-schema, interprets schemas without eval or new Function, and defaults to JSON Schema draft 2020-12.
It is not an AJV replacement. See the package README for the unsupported-keyword matrix and current upstream-state notes.
Differences from `@rjsf/validator-ajv8`
- AJV-only options and extensions such as
AjvClass,$data,discriminator, andajv-errors'serrorMessageare not supported. $dynamicRefand$dynamicAnchorare not currently supported by the underlying engine.- Error messages differ from AJV, and there is no
ajv-i18nlocalizer equivalent. UsetransformErrorsto customize messages. - Precompiled-validator mode is not part of this initial package.
- The wrapper normalizes
undefinedform-data values before validation and caches validators by schema id to make repeated RJSFisValid()calls safe.
Types
The package exports CustomValidatorOptionsType, CFWorkerValidationError, CFWorkerFormatChecker, and SuppressDuplicateFilteringType from src/types.ts.
APIs
`customizeValidator()`
Creates a ValidatorType<T, S, F> backed by @cfworker/json-schema.
Parameters
options.additionalMetaSchemas: additional schemas registered for cross-schema$refresolutionoptions.customFormats: format checkers expressed as functions, regular expressions, or regular-expression source stringsoptions.draft:'4','7','2019-09', or'2020-12'; defaults to'2020-12'options.extenderFn: hook called with every newly constructed engine validatoroptions.shortCircuit: stop at the first error; defaults tofalseoptions.suppressDuplicateFiltering:'none','anyOf','oneOf', or'all'
Returns
ValidatorType<T, S, F>: the customized validator implementation
import { customizeValidator } from '@rjsf/validator-cfworker';
const validator = customizeValidator({
draft: '2020-12',
customFormats: { slug: /^[a-z0-9-]+$/ },
});Packages Docs Docs Json Schema Arrays (`packages/docs/docs/json-schema/arrays.md`)
Arrays
Arrays are defined with a type equal to array, and array items' schemas are specified in the items keyword.
Arrays of a single field
Arrays of a single field type can be specified as follows:
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
items: {
type: 'string',
},
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));Arrays of objects
Arrays of objects can be specified as follows:
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
items: {
type: 'object',
properties: {
name: {
type: 'string',
},
},
},
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));uiSchema for array items
To specify a uiSchema that applies to array items, specify the uiSchema value within the items property:
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
items: {
type: 'string',
},
};
const uiSchema = {
items: {
'ui:widget': 'textarea',
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));NOTE: The
itemsproperty inuiSchemacan also accept a function for dynamic UI schema generation based on array item data. See Dynamic UI Schema Examples for advanced use cases.
The `additionalItems` keyword
The additionalItems keyword allows the user to add additional items of a given schema. For example:
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
items: {
type: 'string',
},
additionalItems: {
type: 'boolean',
},
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));Array item uiSchema options
Any of these options can be set globally if they are contained within the ui:globalOptions block.
They can also be overridden on a per-field basis inside a ui:options block as shown below.
`orderable` option
Array items are orderable by default, and react-jsonschema-form renders move up/down buttons alongside them. The uiSchema orderable options allows you to disable ordering:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
items: {
type: 'string',
},
};
const uiSchema: UiSchema = {
'ui:options': {
orderable: false,
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));`addable` option
If either items or additionalItems contains a schema object, an add button for new items is shown by default. You can turn this off with the addable option in uiSchema:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
items: {
type: 'string',
},
};
const uiSchema: UiSchema = {
'ui:options': {
addable: false,
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));`copyable` option
A copy button is NOT shown by default for an item if items contains a schema object, or the item is an additionalItems instance.
You can turn this ON with the copyable option in uiSchema:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
items: {
type: 'string',
},
};
const uiSchema: UiSchema = {
'ui:options': {
copyable: true,
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));`removable` option
A remove button is shown by default for an item if items contains a schema object, or the item is an additionalItems instance. You can turn this off with the removable option in uiSchema:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
items: {
type: 'string',
},
};
const uiSchema: UiSchema = {
'ui:options': {
removable: false,
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));Multiple-choice list
The default behavior for array fields is a list of text inputs with add/remove buttons. There are two alternative widgets for picking multiple elements from a list of choices. Typically, this applies when a schema has an enum list for the items property of an array field, and the uniqueItems property set to true.
Example:
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
title: 'A multiple-choice list',
items: {
type: 'string',
enum: ['foo', 'bar', 'fuzz', 'qux'],
},
uniqueItems: true,
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));By default, this will render a multiple select box. If you prefer a list of checkboxes, just set the uiSchema ui:widget directive to checkboxes for that field:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
title: 'A multiple-choice list',
items: {
type: 'string',
enum: ['foo', 'bar', 'fuzz', 'qux'],
},
uniqueItems: true,
};
const uiSchema: UiSchema = {
'ui:widget': 'checkboxes',
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));Custom widgets
In addition to ArrayFieldTemplate you use your own widget by providing it to the uiSchema with the property of ui:widget.
Example:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const CustomSelectComponent = (props) => {
return (
<select>
{props.value.map((item, index) => (
<option key={index} id='custom-select'>
{item}
</option>
))}
</select>
);
};
const schema: RJSFSchema = {
type: 'array',
title: 'A multiple-choice list',
items: {
type: 'string',
},
};
const uiSchema: UiSchema = {
'ui:widget': 'CustomSelect',
};
const widgets = {
CustomSelect: CustomSelectComponent,
};
render(
<Form schema={schema} uiSchema={uiSchema} widgets={widgets} validator={validator} />,
document.getElementById('app'),
);Specifying the minimum or maximum number of items
Note that when an array property is marked as required, an empty array is considered valid. If the array needs to be populated, you can specify the minimum number of items using the minItems property.
Example:
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
minItems: 2,
title: 'A multiple-choice list',
items: {
type: 'string',
enum: ['foo', 'bar', 'fuzz', 'qux'],
},
uniqueItems: true,
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));You can also specify the maximum number of items in an array using the maxItems property.
Inline checkboxes
By default, checkboxes are stacked. If you prefer them inline, set the inline property to true:
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'array',
minItems: 2,
title: 'A multiple-choice list',
items: {
type: 'string',
enum: ['foo', 'bar', 'fuzz', 'qux'],
},
uniqueItems: true,
};
const uiSchema: UiSchema = {
'ui:widget': 'checkboxes',
'ui:options': {
inline: true,
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));Packages Docs Docs Json Schema Definitions (`packages/docs/docs/json-schema/definitions.md`)
Schema definitions and references
This library partially supports inline schema definition dereferencing, which allows you to re-use parts of your schema:
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
definitions: {
address: {
type: 'object',
properties: {
street_address: { type: 'string' },
city: { type: 'string' },
state: { type: 'string' },
},
required: ['street_address', 'city', 'state'],
},
},
type: 'object',
properties: {
billing_address: { $ref: '#/definitions/address' },
shipping_address: { $ref: '#/definitions/address' },
},
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));Note that this library only supports local definition referencing. The value in the $ref keyword should be a JSON Pointer in URI fragment identifier format.
uiSchema for Schema Definitions
To customize the UI for schemas referenced via $ref, use the ui:definitions property in your uiSchema. This works for both reused and recursive schemas.
See ui:definitions for full details and more examples.
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
definitions: {
node: {
type: 'object',
properties: {
name: { type: 'string' },
children: {
type: 'array',
items: { $ref: '#/definitions/node' },
},
},
},
},
type: 'object',
properties: {
tree: { $ref: '#/definitions/node' },
},
};
const uiSchema: UiSchema = {
'ui:definitions': {
'#/definitions/node': {
name: { 'ui:placeholder': 'Node name' },
},
},
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));Packages Docs Docs Json Schema Dependencies (`packages/docs/docs/json-schema/dependencies.md`)
Dependencies
react-jsonschema-form supports the dependencies keyword from an earlier draft of JSON Schema (note that this is not part of the latest JSON Schema spec, though). Dependencies can be used to create dynamic schemas that change fields based on what data is entered.
Property dependencies
This library supports conditionally making fields required based on the presence of other fields.
Unidirectional
In the following example the billing_address field will be required if credit_card is defined.
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
name: { type: 'string' },
credit_card: { type: 'number' },
billing_address: { type: 'string' },
},
required: ['name'],
dependencies: {
credit_card: ['billing_address'],
},
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));Bidirectional
In the following example the billing_address field will be required if credit_card is defined and the credit_card
field will be required if billing_address is defined, making them both required if either is defined.
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
name: { type: 'string' },
credit_card: { type: 'number' },
billing_address: { type: 'string' },
},
required: ['name'],
dependencies: {
credit_card: ['billing_address'],
billing_address: ['credit_card'],
},
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));(Sample schemas courtesy of the Space Telescope Science Institute)
Schema dependencies
This library also supports modifying portions of a schema based on form data.
Conditional
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
name: { type: 'string' },
credit_card: { type: 'number' },
},
required: ['name'],
dependencies: {
credit_card: {
properties: {
billing_address: { type: 'string' },
},
required: ['billing_address'],
},
},
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));In this example the billing_address field will be displayed in the form if credit_card is defined.
(Sample schemas courtesy of the Space Telescope Science Institute)
Dynamic
The JSON Schema standard says that the dependency is triggered if the property is present. However, sometimes it's useful to have more sophisticated rules guiding the application of the dependency. For example, maybe you have three possible values for a field, and each one should lead to adding a different question. For this, we support a very restricted use of the oneOf keyword.
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'Person',
type: 'object',
properties: {
'Do you have any pets?': {
type: 'string',
enum: ['No', 'Yes: One', 'Yes: More than one'],
default: 'No',
},
},
required: ['Do you have any pets?'],
dependencies: {
'Do you have any pets?': {
oneOf: [
{
properties: {
'Do you have any pets?': {
enum: ['No'],
},
},
},
{
properties: {
'Do you have any pets?': {
enum: ['Yes: One'],
},
'How old is your pet?': {
type: 'number',
},
},
required: ['How old is your pet?'],
},
{
properties: {
'Do you have any pets?': {
enum: ['Yes: More than one'],
},
'Do you want to get rid of any?': {
type: 'boolean',
},
},
required: ['Do you want to get rid of any?'],
},
],
},
},
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));In this example the user is prompted with different follow-up questions dynamically based on their answer to the first question.
In these examples, the "Do you have any pets?" question is validated against the corresponding property in each schema in the oneOf array. If exactly one matches, the rest of that schema is merged with the existing schema.
Packages Docs Docs Json Schema Objects (`packages/docs/docs/json-schema/objects.md`)
Objects
Object properties
Objects are defined with a type equal to object and properties specified in the properties keyword.
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'My title',
description: 'My description',
type: 'object',
properties: {
name: {
type: 'string',
},
age: {
type: 'number',
},
},
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));Required properties
You can specify which properties are required using the required attribute:
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'My title',
description: 'My description',
type: 'object',
properties: {
name: {
type: 'string',
},
age: {
type: 'number',
},
},
required: ['name'],
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));Specifying property order
Since the order of object properties in Javascript and JSON is not guaranteed, the uiSchema object spec allows you to define the order in which properties are rendered using the ui:order property:
import { Form } from '@rjsf/core';
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
foo: { type: 'string' },
bar: { type: 'string' },
},
};
const uiSchema: UiSchema = {
'ui:order': ['bar', 'foo'],
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));If a guaranteed fixed order is only important for some fields, you can insert a wildcard "*" item in your ui:order definition. All fields that are not referenced explicitly anywhere in the list will be rendered at that point:
import { UiSchema } from '@rjsf/utils';
const uiSchema: UiSchema = {
'ui:order': ['bar', '*'],
};Additional and pattern properties
The additionalProperties keyword allows the user to add properties with arbitrary key names. Set this keyword equal to a schema object:
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
name: {
type: 'string',
},
},
additionalProperties: {
type: 'number',
enum: [1, 2, 3],
},
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));In this way, an add button for new properties is shown by default.
You can also define uiSchema options for additionalProperties by setting the additionalProperties attribute in the uiSchema.
The patternProperties keyword allows the user to add properties with names that match one or more of the specified regular expressions
import { Form } from '@rjsf/core';
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
properties: {
name: {
type: 'string',
},
},
patternProperties: {
'^foo+$': {
type: 'number',
enum: [1, 2, 3],
},
},
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));Also in this case, an add button for new properties is shown by default.
`expandable` option
You can turn support for additionalProperties and patternProperties off with the expandable option in uiSchema:
import { UiSchema } from '@rjsf/utils';
const uiSchema: UiSchema = {
'ui:options': {
expandable: false,
},
};Packages Docs Docs Json Schema Oneof (`packages/docs/docs/json-schema/oneof.md`)
oneOf, anyOf, and allOf
react-jsonschema-form supports custom widgets for oneOf, anyOf, and allOf.
- A schema with
oneOfis valid if exactly one of the subschemas is valid. - A schema with
anyOfis valid if at least one of the subschemas is valid. - A schema with
allOfis valid if all of the subschemas are valid.
oneOf
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
oneOf: [
{
properties: {
lorem: {
type: 'string',
},
},
required: ['lorem'],
},
{
properties: {
ipsum: {
type: 'string',
},
},
required: ['ipsum'],
},
],
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));anyOf
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'object',
anyOf: [
{
properties: {
lorem: {
type: 'string',
},
},
required: ['lorem'],
},
{
properties: {
lorem: {
type: 'string',
},
ipsum: {
type: 'string',
},
},
},
],
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));allOf
When allOf is specified in a schema, react-jsonschema-form uses the @x0k/json-schema-merge library to merge the specified subschemas to create a combined subschema that is valid. For example, the below schema evaluates to a combined subschema of {type: "boolean"}:
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'Field',
allOf: [
{
type: ['string', 'boolean'],
},
{
type: 'boolean',
},
],
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));Packages Docs Docs Json Schema Single (`packages/docs/docs/json-schema/single.md`)
Single fields
The simplest example of a JSON Schema contains only a single field. The field type is determined by the type parameter.
Field types
The base field types in JSON Schema include:
stringnumberintegerbooleannull
Here is an example of a string field:
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'string',
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));Titles and descriptions
Fields can have titles and descriptions specified by the title keyword in the schema and the description keyword in the schema, respectively. These two can also be overridden by the ui:title and ui:description keywords in the uiSchema.
Description can render markdown. This feature is disabled by default. It needs to be enabled by the ui:enableMarkdownInDescription keyword and setting to true. Read more about markdown options in the markdown-to-jsx official docs.
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
title: 'My form',
description: 'My description',
type: 'string',
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));Deprecated fields
The JSON Schema deprecated keyword can be used to indicate that a field is no longer supported.
The deprecated keyword is a JSON Schema Draft 2019-09 feature. You may need to configure your schema validator to properly recognize it. See the Validation documentation for more details.
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'string',
deprecated: true,
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));By default, RJSF will append (deprecated) to the field label. You can customize this behavior using the deprecatedHandling option in the uiSchema. See deprecatedHandling for more details.
Enumerated values
All base schema types support the enum attribute, which restricts the user to select among a list of options. For example:
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'string',
enum: ['one', 'two', 'three'],
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));Custom labels for `enum` fields
JSON Schema supports the following approaches to enumerations using oneOf/anyOf; react-jsonschema-form supports it as well.
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'number',
anyOf: [
{
type: 'number',
title: 'one',
enum: [1],
},
{
type: 'number',
title: 'two',
enum: [2],
},
{
type: 'number',
title: 'three',
enum: [3],
},
],
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));import { RJSFSchema } from '@rjsf/utils';
const schema: RJSFSchema = {
type: 'number',
oneOf: [
{ const: 1, title: 'one' },
{ const: 2, title: 'two' },
{ const: 3, title: 'three' },
],
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));If you use enum in your JSON Schema, you may instead specify ui:enumNames in your uiSchema, which RJSF can use to label an enumeration. ui:enumNames can be an array (matched by index) or a map (matched by value):
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'number',
enum: [1, 2, 3],
};
// Array form (matched by index)
const uiSchema: UiSchema = {
'ui:enumNames': ['one', 'two', 'three'],
};
// Map form (matched by value)
const uiSchema: UiSchema = {
'ui:enumNames': { 1: 'one', 2: 'two', 3: 'three' },
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));Ordering `enum` fields
To control the display order of enum options, use ui:enumOrder. Use '*' to represent all remaining values in their original schema order. Unlisted values not covered by '*' are dropped.
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'string',
enum: ['apple', 'banana', 'cherry', 'date'],
};
const uiSchema: UiSchema = {
'ui:enumOrder': ['cherry', '*', 'apple'],
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));Disabled attribute for `enum` fields
To disable an option, use the ui:enumDisabled property in the uiSchema.
import { RJSFSchema, UiSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: 'boolean',
enum: [true, false],
};
const uiSchema: UiSchema = {
'ui:enumDisabled': [true],
};
render(<Form schema={schema} uiSchema={uiSchema} validator={validator} />, document.getElementById('app'));Nullable types
JSON Schema supports specifying multiple types in an array; however, react-jsonschema-form only supports a restricted subset of this -- nullable types, in which an element is either a given type or equal to null.
import { RJSFSchema } from '@rjsf/utils';
import validator from '@rjsf/validator-ajv8';
const schema: RJSFSchema = {
type: ['string', 'null'],
};
render(<Form schema={schema} validator={validator} />, document.getElementById('app'));Packages Docs Docs Migration Guides V2.X Upgrade Guide (`packages/docs/docs/migration-guides/v2.x upgrade guide.md`)
2.x Upgrade Guide
Changes from v1 -> v2
Breaking changes
- We now officially support the @rjsf/material-ui theme. We use a monorepo with Lerna and have published two packages (@rjsf/core and @rjsf/material-ui) with this version number. Note that react-jsonschema-form has been renamed to @rjsf/core (#1642)
- Combine all themes into a single playground (#1539, #1607, #1623)
- Remove ui:order console warning about extraneous properties (#1508)
- Capitalized Yes and No defaults (#1395)
- Fix id of oneof and anyof select (#1212). The oneof select id is now suffixed by __oneof_select and the anyof select by __anyof_select.
- React 16+ is now a peer dependency (#1408)
- We no longer actively support Node version < 8 (#1462)
- Removed setState, setImmediate, safeRenderCompletion helpers/hacks (#1454, #1720)
- Inject defaults in arrays (#1499)
Features
- Add material-ui theme in the main repo (#1420) (note: has not been fully integrated yet -- this will be fully integrated when we publish multiple packages with lerna - #1501)
- Add extraErrors prop for async validation (#1444)
- Add support for overriding UnsupportedField (#1660)
Fixes
- Fix issue with false as formData on radio components (#1438)
- Security patches (#1458, #1459)
- Memo components in custom widgets and fields. (#1447)
- Introduce Form autoComplete attribute and deprecate autocomplete (#1483)
- Rewrite mergeSchemas to fix schema dependencies merging (#1476)
- Update arrays correctly when changing index (#1485)
- Update anyOf schema to correctly update items in an array (#1491)
- Update schema to re-render when idschema changes (#1493)
- Make sure BooleanField supports an overridable DescriptionField (#1594)
- Export typings (#1607)
Packages Docs Docs Migration Guides V3.X Upgrade Guide (`packages/docs/docs/migration-guides/v3.x upgrade guide.md`)
3.x Upgrade Guide
Breaking changes
Node support
Dropped support for Node 8, 9, 10. Minimum supported version of Node.js is now 12.
Dereferenced schemas for `anyOf`/`allOf` options
MultiSchemaField's options interface is different. Before, an option could include a $ref. Now, any option with a reference will be resolved/dereferenced when given as props for MultiSchemaField.
Help field IDs
IDs for Help fields are now suffixed by __help so that the IDs are unique. Previously, their IDs would be nonexistent or the same as the fields that they were describing.
Bring your own polyfills
core-js@2 has been removed from @rjsf/core. See more about the rationale here.
If you're using a framework like Create React App, Gatsby, Next.js, or transpiling code through something like @babel/preset-env, polyfills are already included there and you won't have to do anything.
If you were directly depending on @rjsf/core's @babel/runtime pulling in core-js@2, just npm install core-js and using a side effectful import at the top of your entry point (import 'core-js') might be enough.
For a slightly more elaborate setup, @babel/preset-env is probably a good second choice.
From @babel/preset-env's docs
We leverage [
browserslist,compat-table, andelectron-to-chromium] to maintain mappings of which version of our supported target environments gained support of a JavaScript syntax or browser feature, as well as a mapping of those syntaxes and features to Babel transform plugins and core-js polyfills.
Packages Docs Docs Migration Guides V4.X Upgrade Guide (`packages/docs/docs/migration-guides/v4.x upgrade guide.md`)
4.x Upgrade Guide
Breaking changes
React version
No longer actively supporting React version < 16.3. The minimum supported version of React is now 16.3. Discussion can be found here
@rjsf/material-ui package - Minimum version of material-ui 4
If you are using the material-ui 4 theme, @material-ui/core and @material-ui/icons packages should be updated to the latest versions. The minimum versions supported for @material-ui/core and @material-ui/icons are 4.12.0 and 4.11.1 respectively. This change is required for support for the material-ui version 5 theme
Packages Docs Docs Migration Guides V5.X Upgrade Guide (`packages/docs/docs/migration-guides/v5.x upgrade guide.md`)
5.x Upgrade Guide
Breaking changes
There were several significant breaking changes in RJSF version 5 that were necessary in order to support the following new features:
- Schema validation was decoupled from
@rjsf/coreto resolve issue #2693. Additionally, in order to break a circular dependency in the validation refactor, the@rjsf/core/utils.jsfile was split out into its own@rjsf/utilspackage as was suggested in #1655. - The theme for Material UI version 5 (i.e.
@rjsf/mui) was split out of the theme for version 4 (i.e.@rjsf/material-ui) to resolve the following issues: #2762, #2858, #2905, #2945 - As part of the fix for #2526 all the existing templates in the previous version were moved into a new
templatesdictionary, similar to howwidgetsandfieldswork. Thistemplatesdictionary was added to theRegistryand also theFormprops, replacing theArrayFieldTemplate,FieldTemplate,ObjectFieldTemplateandErrorListprops. In addition, several of thefieldsandwidgetsbased components were moved into thetemplatesdictionary as they were more like templates than trueFields orWidgets. Also fixes #2945 - Fixed
anyOfandoneOfgetting incorrect, potentially duplicate ids when combined with array #2197 CheckboxesWidget,RadioWidgetandSelectWidgetin all themes now use indexes intoenumOptions[]rather thanoption.valueto allow for objects inenumOptions- #1494
Node support
Version 5 is dropping official support for Node 12 as it is no longer a maintained version.
Please use Node 18 when making any changes to package.json and package-lock.json files.
All PR and branch builds are running against Node 14, 16 and 18.
React version
RJSF is no longer actively supporting React version < 16.14.x.
React 17 is officially supported on all the themes where the underlying theme library also supports React 17.
Unfortunately, there is required work pending to properly support React 18, so use it at your own risk.
New packages
There are four new packages added in RJSF version 5:
@rjsf/utils: All of the utility functions previously imported from@rjsf/core/utilsas well as the Typescript types for RJSF version 5.- The following new utility functions were added:
ariaDescribedByIds(),createSchemaUtils(),descriptionId(),enumOptionsDeselectValue(),enumOptionsIndexForValue(),enumOptionsIsSelected(),enumOptionsSelectValue(),enumOptionsValueForIndex(),errorId(),examplesId(),getClosestMatchingOption(),getFirstMatchingOption(),getInputProps(),helpId(),mergeValidationData(),optionId(),sanitizeDataForNewSchema()andtitleId()
- The following new utility functions were added:
@rjsf/validator-ajv6: The ajv-v6-based validator refactored out of@rjsf/[email protected], that implements theValidatorTypeinterface defined in@rjsf/utils.@rjsf/validator-ajv8: The ajv-v8-based validator that is an upgrade of the@rjsf/validator-ajv6, that implements theValidatorTypeinterface defined in@rjsf/utils. See the ajv 6 to 8 migration guide for more information.@rjsf/mui: Previously@rjsf/material-ui/v5, now provided as its own theme.
`id` BREAKING CHANGES
In many of the themes the ids for the Title, Description and Examples blocks were update to all have a consistent value of xxx__title, xxx__description and xxx__examples, respectively, where xxx is the id of the field.
In addition, some of the ids for various input values were updated to be consistent across themes or to fix small bugs.
For instance, the values for radio buttons in the RadioWidget and checkboxes in the CheckboxesWidget are of the form xxx-${option.value}, where xxx is the id of the field.
`enumOptions[]` widgets BREAKING CHANGES
Schemas may have enumOptions[] where values are objects rather than primitive types. Examples of such schemas have been added to the playground. These schemas did not work in RJSF prior to v5.
In every theme, the enumOptions[] rendering widgets CheckboxesWidget, RadioWidget and SelectWidget previously used the enumOptions[].value to as the value used for the underlying checkbox, radio and select.option elements.
Now, these CheckboxesWidget, RadioWidget and SelectWidget components use the index of the enumOptions[] in the list as the value for the underlying elements.
If you need to build a custom widget for this kind of enumOptions, there are a set of enumOptionsXXX functions in @rjsf/utils to support your implementation.
`@rjsf/core` BREAKING CHANGES
Types
In version 4, RJSF exported all its types directly from @rjsf/core.
In version 5, only the types for the Form component and the withTheme() HOC are exported directly from @rjsf/core.
All the rest of the types for RJSF are now exported from the new @rjsf/utils package.
NOTE: The types in @rjsf/utils have been improved significantly from those in version 4 and as a result may require you to fix your Typescript typings and add some casts.
Some of the most notable changes are:
RJSFSchemahas replaced the use ofJSON7Schemafor future compatibility reasons.- Currently
RJSFSchemais simply an alias toJSON7Schemaso this change is purely a naming one. - It is highly recommended to update your use of
JSON7SchemawithRJSFSchemaso that when the RJSF begins supporting a newer JSON Schema version out-of-the-box, your code won't be affected.
- Currently
RJSFSchemaDefinitionhas replaced the use ofJSONSchema7Definitionfor the same reasons.The use of the generic
T(defaulting toany) for theformDatatype has been expanded to cover all type hierarchies that useformData.StrictRJSFSchemaandRJSFSchemahave replaced the use ofJSON7Schemafor future compatibility reasons.RJSFSchemaisStrictRJSFSchemajoined with theGenericObjectType(i.e.{ [key: string]: any }) to allow for additional syntax related to newer draft versions- All definitions of
schemaandrootSchemaelements have been replaced with a generic that is defined asS extends StrictRJSFSchema = RJSFSchema - It is highly recommended to update your use of
JSON7SchemawithRJSFSchemasince that is the default for the new generic used forschemaandrootSchema
A new generic
F(extendingFormContextTypedefaulting toany) was added for theformContexttype, and all types in the hierarchy that useformContexthave had that generic added to them.The new
CustomValidator,ErrorTransformer,ValidationData,ValidatorTypeandSchemaUtilsTypetypes were added to support the decoupling of the validation implementation.The new
TemplatesType,ArrayFieldDescriptionProps,ArrayFieldTitleProps,UnsupportedFieldProps,IconButtonProps,SubmitButtonPropsandUIOptionsBaseTypewere added to support the consolidation (and expansion) oftemplatesin theRegistryandForm.BREAKING CHANGE The
DescriptionFieldandTitleFieldprops were removed from theArrayFieldTemplatePropsandObjectFieldTemplatePropsas they can now be derived from thetemplatesoruiSchemavia the newgetTemplate()utility function.BREAKING CHANGE The
fieldsprop was removed from theFieldTemplatePropsas you can simply useregistry.fieldsinstead.BREAKING CHANGE The
showErrorListprop was changed to acceptfalse,"top"or"bottom".trueis no longer a valid value. The default value is"top", which has identical behavior to the default value/truein v4.
You can view all these types on GitHub.
Form props
In version 5, the Form component's two optional props additionalMetaSchemas and customFormats were replaced with the new, required validator prop, in order to support the decoupling of the validation implementation.
This new validator prop is expected to be an implementation of the ValidatorType interface.
The new @rjsf/validator-ajv6 package contains the refactored implementation of the version 4 validator; It was provided for backwards compatibility with RJSF v4, and it is deprecated.
The new @rjsf/validator-ajv8 package contains the refactored implementation of the version 4 validator, that has been converted to use the Ajv 8 validator and has more capabilities than the Ajv 6 one. See the Ajv migration guide for more information.
There are two ways to use this new package to provide a validator for a Form.
First, you can simply import the default validator from the package and pass it to a Form.
import { RJSFSchema } from "@rjsf/utils";
import Form from "@rjsf/core";
import validator from "@rjsf/validator-ajv8";
// Your schema
const schema: RJSFSchema = { ... };
render((
<Form schema={schema} validator={validator} />
), document.getElementById("app"));Second, if you were actually providing one (or both) of the removed optional props to your Form, you can continue using them by creating a customized validator.
import { RJSFSchema } from "@rjsf/utils";
import Form from "@rjsf/core";
import { customizeValidator, CustomValidatorOptionsType } from "@rjsf/validator-ajv8";
// Your schema, additionalMetaSchemas and/or customFormats
const schema: RJSFSchema = { ... };
const additionalMetaSchemas: CustomValidatorOptionsType['additionalMetaSchemas'] = [{ ... }];
const customFormats: CustomValidatorOptionsType['customFormats'] = { ... };
const validator = customizeValidator({ additionalMetaSchemas, customFormats });
render((
<Form schema={schema} validator={validator} />
), document.getElementById("app"));`formElement` converted to RefObject
The formElement variable that stored the ref to the inner <form /> was converted from a simple variable assigned via a callback ref (ala React < 16.3) to a React.RefObject created using the React.createRef() API.
As a result, if you were using the formElement ref, you will need to update it to use formElement.current:
import { RJSFSchema } from "@rjsf/utils";
import Form from "@rjsf/core";
import validator from "@rjsf/validator-ajv8";
// Your schema
const schema: RJSFSchema = { ... };
const formRef = React.createRef();
render((
<Form ref={formRef} schema={schema} validator={validator} />
), document.getElementById("app"));
...
// Previously, to reset the form one would have called:
// formRef.current.formElement.reset();
// Now one calls:
formRef.current.formElement.current.reset();`validate` prop renamed
Additionally, in version 5, the validate prop on Form was renamed to customValidate to avoid confusion with the new validator prop.
`fields` prop changes
In previous versions, it was possible to provide an override to the DescriptionField, TitleField and/or UnsupportedField components by providing a custom implementation in the fields prop on the Form.
Since these components do not actually support the FieldProps interface, they were moved into the templates dictionary instead.
If you were previously overriding any (or all) of these components, you can override them now via the templates prop on Form instead:
import { DescriptionFieldProps, RJSFSchema, TitleFieldProps } from "@rjsf/utils";
import Form from "@rjsf/core";
import validator from "@rjsf/validator-ajv8";
// Your schema
const schema: RJSFSchema = { ... };
// Your custom fields
const CustomDescriptionField = (props: DescriptionFieldProps) => { ... };
const CustomTitleField = (props: TitleFieldProps) => { ... };
const CustomUnsupportedField = (props: ObjectFieldTemplateProps) => { ...
};
const templates: Partial<TemplatesType> = {
DescriptionFieldTemplate: CustomDescriptionField,
TitleFieldTemplate: CustomTitleField,
UnsupportedFieldTemplate: CustomUnsupportedField,
};
render((
<Form schema={schema} validator={validator} templates={templates}/>
), document.getElementById("app"));new `templates` prop
Additionally, in version 5, the ArrayFieldTemplate, FieldTemplate, ObjectFieldTemplate and ErrorList props were replaced with the templates prop as part of the TemplatesType consolidation.
If you were previously overriding any (or all) of these templates, you can simply consolidate them into the new templates prop on Form instead:
import { ArrayFieldTemplateProps, ErrorListProps, FieldTemplateProps, ObjectFieldTemplateProps, RJSFSchema } from "@rjsf/utils";
import Form from "@rjsf/core";
import validator from "@rjsf/validator-ajv8";
// Your schema
const schema: RJSFSchema = { ... };
// Your custom templates
const CustomArrayFieldTemplate = (props: ArrayFieldTemplateProps) => { ... };
const CustomFieldTemplate = (props: FieldTemplateProps) => { ... };
const CustomObjectFieldTemplate = (props: ObjectFieldTemplateProps) => { ... };
const CustomErrorField = (props: ErrorListProps) => { ... };
const templates: Partial<TemplatesType> = {
ArrayFieldTemplate: CustomArrayFieldTemplate,
FieldTemplate: CustomFieldTemplate,
ObjectFieldTemplate: CustomObjectFieldTemplate,
ErrorFieldTemplate: CustomErrorField,
};
render((
<Form schema={schema} validator={validator} templates={templates} />
), document.getElementById("app"));NOTE: In version 5, the ArrayField implementation was refactored to add 3 additional templates for presenting arrays along with the ArrayFieldTemplate.
If you were updating the ArrayFieldTemplate to modify just a subset of the UI, it may be easier for you to implement one of the other new templates instead.
See the Custom Templates documentation for more details.
`widgets` prop change
In the previous version, it was possible to provide an override to the SubmitButton component by providing a custom implementation in the widgets prop on the Form.
Since this component only requires a tiny fraction of the WidgetProps interface, it was moved into the templates.ButtonTemplates dictionary instead with its own, reduced set of props.
If you were previously overriding this component, you can override it now via the templates prop on Form instead:
import { RJSFSchema, SubmitButtonProps } from "@rjsf/utils";
import Form from "@rjsf/core";
import validator from "@rjsf/validator-ajv8";
// Your schema
const schema: RJSFSchema = { ... };
// Your custom button
const CustomSubmitButton = (props: SubmitButtonProps) => { ...
};
const templates: Partial<TemplatesType> = {
ButtonTemplates: {
SubmitButton: CustomSubmitButton,
}
};
render((
<Form schema={schema} validator={validator} templates={templates}/>
), document.getElementById("app"));utils.js
In version 5, all the utility functions that were previously accessed via import { utils } from '@rjsf/core'; are now available via import utils from '@rjsf/utils';.
Because of the decoupling of validation from @rjsf/core there is a breaking change for all the validator-based utility functions, since they now require an additional ValidatorType parameter.
More over, one previously exported function resolveSchema() is no longer exposed in the @rjsf/utils, so use retrieveSchema() instead.
Finally, the function getMatchingOption() has been deprecated in favor of getFirstMatchingOption().
If you have built custom fields or widgets that utilized any of these breaking-change functions, don't worry, there is a quick and easy solution for you.
The registry has a breaking-change which removes the previously deprecated definitions property while adding the new schemaUtils property.
This new registry.schemaUtils property implements the SchemaUtilsType interface, which allows you to call a version of each of these breaking-change functions without the need for passing either a validator or rootSchema.
Because all fields and widgets are guaranteed to be passed the registry as a prop, if your custom field/widget happens to use either the registry.definitions object or a breaking-change validator-based utility function you make the following changes:
import { RJSFSchema, FieldProps } from '@rjsf/utils';
function YourField(props: FieldProps) {
const { registry } = props;
// Change `registry.definitions` to `registry.rootSchema.definitions`
// const { definitions } = registry; <- version 4
const { rootSchema } = registry;
const { definitions } = rootSchema;
...
}// Change breaking-change function to schemaUtils instead, otherwise import from @rjsf/utils
// import { utils } from '@rjsf/core'; <- version 4
// const { isMultiSelect, resolveSchema, getUiOptions } = utils; <- version 4
import { RJSFSchema, WidgetProps, getUiOptions } from '@rjsf/utils';
function YourWidget(props: WidgetProps) {
const { registry, uiSchema } = props;
const { schemaUtils } = registry;
// const matchingOption = getMatchingOption({}, options, rootSchema); <- version 4
// const isMultiSelect = isMultiSelect(schema, rootSchema); <- version 4
// const newSchema = resolveSchema(schema, formData, rootSchema); <- version 4
const matchingOption = schemaUtils.getFirstMatchingOption({}, options);
const isMultiSelect = schemaUtils.isMultiSelect(schema);
const newSchema: RJSFSchema = schemaUtils.retrieveSchema(schema, formData);
const options = getUiOptions(uiSchema);
...
}validator.js
Because of the decoupling of validation from @rjsf/core this file was refactored into its own @rjsf/validator-ajv8 package.
During that refactor a few breaking changes were made to how it works related to custom validation and ErrorSchema conversion.
toErrorList param changed
In previous versions, the toErrorList() function used to take a fieldName string defaulted to root, and used it to format the stack message.
In version 5, fieldName was changed to fieldPath string array defaulted to an empty array, and is used to recursively add the field name to the errors as the property object along with the raw message.
The result is that if you had an ErrorSchema that looks like:
const errorSchema: ErrorSchema = {
__errors: ['error message 1'],
password: { __errors: 'passwords do not match' },
};The returned result from calling toErrorList(errorSchema) has changed as follows:
// version 4 result
[{ stack: 'root: error message 1' }, { stack: 'password: passwords do not match' }][
// version 5 result
({ property: '.', message: 'error message 1', stack: '. error message 1' },
{
property: '.password',
message: 'passwords do not match',
stack: '.password passwords do not match',
})
];Custom validation and extraErrors
In previous versions, when using a custom validator on the Form, any errors that were generated were inconsistently inserted into the validations errors list.
In addition, there was an issue where the non-stack AJV error information was lost when custom validation generated errors.
This issue has been fixed.
Also, when extraErrors were provided, they were being inconsistently inserted into the errors list and the non-stack AJV error information was lost.
In version 5, all of these errors will be consistently appended onto the end of the validation errors list, and the additional AJV error information is maintained.
In other words, if custom validation or extraErrors produced the following ErrorSchema:
{
__errors: [ "Please correct your password"],
password2: { __errors: "passwords do not match" }
}And the AJV validation produced the following ErrorSchema:
{
__errors: [
{
message: 'should NOT be shorter than 3 characters',
name: 'minLength',
params: { limit: 3 },
property: '.password2',
schemaPath: '#/properties/password2/minLength',
stack: '.password2 should NOT be shorter than 3 characters',
},
];
}The resulting errors list has changed as follows:
// version 4
[
{ stack: 'root: Please correct your password' },
{ stack: 'password2: passwords do not match' },
{ stack: 'password2: should NOT be shorter than 3 characters' },
][
// version 5
({
message: 'should NOT be shorter than 3 characters',
name: 'minLength',
params: { limit: 3 },
property: '.password2',
schemaPath: '#/properties/password2/minLength',
stack: '.password2 should NOT be shorter than 3 characters',
},
{
property: '.',
message: 'Please correct your password',
stack: '. Please correct your password',
},
{
property: '.',
message: 'passwords do not match',
stack: '.password2 passwords do not match',
})
];Generate correct ids when arrays are combined with `anyOf`/`oneOf`
In v4, with arrays inside anyOf or oneOf, the parent name was not used to generate ids.
For example, given a schema such as:
{
"type": "object",
"properties": {
"items": {
"type": "array",
"items": {
"type": "object",
"anyOf": [
{
"properties": {
"foo": {
"type": "string"
}
}
},
{
"properties": {
"bar": {
"type": "string"
}
}
}
]
}
}
}
}We would get fields with id root_foo and root_bar.
As you can imagine, we could end up with duplicated ids if there's actually a foo or a bar in the root of the schema.
From v5, the child fields will correctly use the parent id when generating its own id, generating ids such as root_items_0_foo.
Deprecations added in v5
getMatchingOption()
The utility function getMatchingOption() was deprecated in favor of the more aptly named getFirstMatchingOption() which has the exact same implementation.
Non-standard `enumNames` property
enumNames is a non-standard JSON Schema field that was deprecated in version 5.enumNames could be included in the schema to apply labels that differed from an enumeration value.
This behavior can still be accomplished with oneOf or anyOf containing const values, so enumNames support will be removed from a future major version of RJSF.
For more information, see #532.
uiSchema.classNames
In versions previous to 5, uiSchema.classNames was the only property that did not require the ui: prefix.
Additionally, it did not support being added into the ui:options object.
This was fixed in version 5 to be consistent with all the other properties in the uiSchema, so the uiSchema.classNames support may be removed from a future major version of RJSF.
If you are using classNames as follows, simply add the ui: prefix to it to remove the deprecation warning that will be displayed for each uiSchema.classNames you have:
import { UiSchema } from '@rjsf/utils';
// This uiSchema will log a deprecation warning to the console
const uiSchemaLog: UiSchema = {
title: {
classNames: 'myClass',
},
};
// This uiSchema will not
const uiSchemaNoLog: UiSchema = {
title: {
'ui:classNames': 'myClass',
},
};`@rjsf/material-ui` BREAKING CHANGES
This theme was simplified back to working only with Material UI version 4 after an unsuccessful attempt to have it fully support both versions 4 and 5 simultaneously.
As a result, the MuiComponentContext, MuiForm5, Theme5 components and the useMuiComponent hook were removed from the export.
In addition, the /v4 and /v5 sub-packages were also removed.
Migrating for Material UI version 4
If you were using this theme for Material UI version 4 AND you were using the sub-package, simply remove the /v4 from your imports.
If you modified your Typescript configuration for the /v4 sub-package, remove the following from your tsconfig.json:
{
...
"compilerOptions": {
...
"baseUrl": ".",
"paths": {
"@rjsf/material-ui/*": ["node_modules/@rjsf/material-ui/dist/*"]
}
}
}If you modified your Jest configuration for the /v4 sub-package, remove the following from your jest.config.json:
"moduleNameMapper": {
"@rjsf/material-ui/v4": "<rootDir>/node_modules/@rjsf/material-ui/dist/v4.js"
},Migrating for Material UI version 5
If you were using this theme for Material UI version 5, you will want to use @rjsf/mui instead.
See below for some before and after examples.
If you modified your Typescript configuration for the /v5 sub-package, remove the following from your tsconfig.json:
{
...
"compilerOptions": {
...
"baseUrl": ".",
"paths": {
"@rjsf/material-ui/*": ["node_modules/@rjsf/material-ui/dist/*"]
}
}
}If you modified your Jest configuration for the /v5 sub-package, remove the following from your jest.config.json:
"moduleNameMapper": {
"@rjsf/material-ui/v5": "<rootDir>/node_modules/@rjsf/material-ui/dist/v5.js"
},Before
import Form5 from '@rjsf/material-ui';or
import Form from '@rjsf/material-ui/v5';or
import { withTheme } from '@rjsf/core';
import { Theme } from '@rjsf/material-ui/v5';
// Make modifications to the theme with your own fields and widgets
const Form = withTheme(Theme);or
import { withTheme } from '@rjsf/core';
import { Theme as Theme5 } from '@rjsf/material-ui';
// Make modifications to the theme with your own fields and widgets
const Form = withTheme(Theme5);After
import Form from '@rjsf/mui';or
import { withTheme } from '@rjsf/core';
import { Theme } from '@rjsf/mui';
// Make modifications to the theme with your own fields and widgets
const Form = withTheme(Theme);Packages Docs Docs Migration Guides V6.X Upgrade Guide (`packages/docs/docs/migration-guides/v6.x upgrade guide.md`)
6.x Upgrade Guide
New packages
There are 5 new packages added in RJSF version 6:
@rjsf/daisyui: This is new theme based on thedaisyuitoolkit@rjsf/mantine: This is new theme based on themantinetoolkit@rjsf/primereact: This is a new theme based on thePrimeReacttoolkit@rjsf/react-bootstrap: This is rename of thebootstrap-4theme with an upgrade to the latest version ofreact-bootstrap@rjsf/shadcn: This is new theme based on theshadcntoolkit
New deprecations
UiSchema.rootFieldId
The ui:rootFieldId notation on UiSchema was deprecated in favor of Form.idPrefix.
This notation will be removed in a future major version release
@rjsf/semantic-ui
The semantic-ui theme is deprecated and will be removed in a future major version 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.
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 requiringchakra-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
Version 6 is dropping official support for semantic-ui-react version 1. You must upgrade to version 2.
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).
Form POTENTIAL BREAKING CHANGES
The onChange() and onSubmit() callbacks were accidentally returning extra data along with what was listed in the IChangeEvent interface.
In v6, this was fixed so that only the data described by the IChangeEvent interface is returned.
If you were relying on that extra data in the callbacks, we are sorry for the inconvenience.
A bug was fixed such that live validation will no longer be triggered on the data provided during the initial rendering of the Form.
If you require that your initial data have errors shown, then you can programmatically validate it after the initial render.
IdSchema replacement BREAKING CHANGE
The recursive IdSchema type and all its usages was replaced with a much simpler FieldPathId type.
This was done to remove a performance headache associated with having to recursively generate the IdSchema for every change made to formData.
Moreover, after some evaluation, 99% of the use cases for the IdSchema were simply to get the id for a field.
FieldPathId is defined as:
/** The list of path elements that represents where in the schema a field is located. When the item in the field list is
* a string, then it represents the name of the property within an object. When it is a number, then it represents the
* index within an array.
*
* For example:
* `[]` represents the root object of the schema
* `['foo', 'bar']` represents the `bar` element contained within the `foo` element of the schema
* `['baz', 1]` represents the second element in the list `baz` of the schema
*/
export type FieldPathList = (string | number)[];
/** Type describing an id and path used for a field */
export type FieldPathId = {
/** The id for a field */
$id: string;
/** The path for a field */
path: FieldPathList;
};idSchema props
In addition, everywhere the idSchema: IdSchema<T> prop was part of a RJSF type, it was replaced with fieldPathId: FieldPathId.
The affected types are:
- FieldErrorProps
- FieldHelpProps
- FieldProps
- UnsupportedFieldProps
- ArrayFieldTitleProps
- ArrayFieldDescriptionProps
- ArrayFieldItemButtonsTemplateProps
- ArrayFieldTemplateProps
- ObjectFieldTemplateProps
If you have built a custom component using one of those types that used idSchema: IdSchema, simply replace that type and property name with fieldPathId: FieldPathId.
For example, if you had a custom field:
import { FieldProps } from '@rjsf/utils';
// Version 5-based custom widget
function CustomField(props: FieldProps) {
const {
idSchema: { $id },
formData,
value,
} = props;
return <div id={$id}>// Your field implementation</div>;
}
// Version 6-based custom widget
function CustomField(props: FieldProps) {
const {
fieldPathId: { $id },
formData,
value,
} = props;
return <div id={$id}>// Your field implementation</div>;
}toIdSchema() removed
Finally, the toIdSchema() utility function was deleted and replaced with a new toFieldPathId() function documented here
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 anErrorListTemplateimplementationFieldProps- The properties that are passed to aFieldimplementationFieldTemplateProps- The properties that are passed to aFieldTemplateimplementationArrayFieldTemplateProps- The properties that are passed to anArrayFieldTemplateimplementationWidgetProps- The properties that are passed to aWidgetimplementation
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 Fields.
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: FieldPathList, es?: ErrorSchema<T>, id?: string) => void;In order to support letting the Form know what the path of the change was, a new path: FieldPathList 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 the fieldPathId.path to the onChange function.
Here is an example of a custom Field that was updated due to this change:
/* Detailed source-code truncated for AI context efficiency. */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.
Finally, the errors are preserved across validations, so if you want to clear an error you passed via onChange, you will have to pass undefined
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: FieldPathList, 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} />;
}FieldProps.idPrefix and FieldProps.idSeparator refactor
The idPrefix and idSeparator props were refactored from the FieldProps interface to the new GlobalFormOptions interface,
If your custom implementation required either of those props, you can simply obtain them from the registry.globalFormOptions variable instead.
FieldTemplateProps and WrapIfAdditionalTemplateProps BREAKING CHANGES
During the conversion of ObjectField to a stateless functional component, the additionalProperties-based props in these two interfaces were simplified by replacing two callback-generators with memoized callbacks.
If you have your own implementation of the FieldTemplate and/or WrapIfAdditionalTemplate template(s), you will have to rename the props mentioned below with their replacements.
onKeyChange replacement
The onKeyChange: (value: string) => () => void callback-generator function was replaced with the following 2 memoized callbacks, (one is a helper callback, since most of the key renames were triggered off of an input blur):
/** Callback used to handle the changing of an additional property key's name with the new value
*/
onKeyRename: (newKey: string) => void;
/** Callback used to handle the changing of an additional property key's name when the input is blurred. The event's
* target's value will be used as the new value. Its a wrapper callback around `onKeyRename`
*/
onKeyRenameBlur: (event: FocusEvent<HTMLInputElement>) => void;onDropPropertyClick replacement
The onDropPropertyClick: (value: string) => () => void callback-generator function was replaced with the following memoized callback:
/** Callback used to handle the removal of the additionalProperty */
onRemoveProperty: () => void;ObjectFieldTemplateProps BREAKING CHANGES
During the conversion of ObjectField to a stateless functional component, the additionalProperties-based prop in this interface was simplified by replacing a callback-generator with a memoized callback.
If you have your own implementation of the ObjectFieldTemplate template, you will have to rename the prop mentioned below with its replacement.
onAddClick replacement
The onAddClick: (schema: S) => () => void callback-generator function was replaced with the following memoized callback:
/** Callback to use in order to add an new additionalProperty to the object field (to be used with
* additionalProperties and patternProperties)
*/
onAddProperty: () => void;Registry BREAKING CHANGES
A new required prop, globalFormOptions: GlobalFormOptions, was added to the Registry interface.
This could affect your tests if you have your own way of creating registry objects to test your custom widgets, fields and/or templates.
If you are creating Registry objects, you simply need to add an empty object to the globalFormOptions prop.
You may also, provide values for any of the optional props contained within the GlobalFormOptions type.
The definition of the GlobalFormOptions object is:
/** The set of options from the `Form` that will be available on the `Registry` for use in everywhere the `registry` is
* available.
*/
export type GlobalFormOptions = {
/** To avoid collisions with existing ids in the DOM, it is possible to change the prefix used for ids;
* Default is `root`. This prop is passed to the `toFieldPathId()` function within the RJSF field implementations.
*/
readonly idPrefix?: string;
/** To avoid using a path separator that is present in field names, it is possible to change the separator used for
* ids; Default is `_`. This prop is passed to the `toFieldPathId()` function within the RJSF field implementations.
*/
readonly idSeparator?: string;
/** The component update strategy used by the Form and its fields for performance optimization */
readonly experimental_componentUpdateStrategy?: 'customDeep' | 'shallow' | 'always';
/** Optional function to generate custom HTML name attributes for form elements. Receives the field path segments
* and element type (object or array), and returns a custom name string. This allows backends like PHP/Rails
* (`root[tasks][0][title]`) or Django (`root__tasks-0__title`) to receive form data in their expected format.
*/
readonly nameGenerator?: NameGeneratorFunction;
};To help support this change for test writers, a new getTestRegistry() function has been provided in @rjsf/core.
Templates BREAKING CHANGES
ArrayFieldTemplateItemType renamed
The type ArrayFieldTemplateItemType was renamed to ArrayFieldItemTemplateProps type, which matches the template properties naming pattern.
Also changed the key: string prop to itemKey: string to avoid a name collision with React
ArrayFieldItemTemplate BREAKING CHANGES
The ArrayFieldItemTemplateProps was refactored to extract the following props into out a new ArrayFieldItemButtonsTemplateProps:
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.onCopyIndexClick: (index: number) => (event?: any) => void;: Returns a function that copies the item atindexinto the position atindex + 1.onDropIndexClick: (index) => (event?) => void: Returns a function that removes the item atindex.onReorderClick: (index, newIndex) => (event?) => void: Returns a function that swaps the items atindexwithnewIndex.
In addition to this refactor, the conversion of the ArrayField template to functional components caused the replacement of the 4 callback-generator functions with 5 memoizable functions.
onAddIndexClick replacement
The onAddIndexClick: (index) => (event?) => void callback-generator function was replaced with the following memoized callback:
/** Callback function that adds a new item below this item */
onAddItem: (event?: any) => void;onCopyIndexClick replacement
The onCopyIndexClick: (index: number) => (event?: any) => void; callback-generator function was replaced with a simpler, memoized callback:
/** Callback function that copies this item below itself */
onCopyItem: (event?: any) => void;onDropIndexClick replacement
The onDropIndexClick: (index) => (event?) => void callback-generator function was replaced with the following memoized callback:
/** Callback function that removes the item from the list */
onRemoveItem: (event?: any) => void;onReorderClick replacement
The onReorderClick: (index, newIndex) => (event?) => void callback-generator function was replaced with the following 2 memoized callbacks:
/** Callback function that moves the item up one spot in the list */
onMoveUpItem: (event?: any) => void;
/** Callback function that moves the item down one spot in the list */
onMoveDownItem: (event?: any) => void;A new buttonsProps prop was added of the type ArrayFieldItemButtonsTemplateProps
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.
ArrayFieldTemplate BREAKING CHANGE
In order to support the conversion of ArrayField to functional components, the items property was changed from an
array of ArrayFieldItemTemplateProps information to an array of React elements. These elements are result of the ArrayField
actually rendering the ArrayFieldItemTemplate directly, rather than deferring it the ArrayFieldTemplate.
If you previously provided a custom ArrayFieldTemplate to do the full rendering of your arrays, now you will have to
separate the logic of generating the items into your own custom ArrayFieldItemTemplate. For example:
/* Detailed source-code truncated for AI context efficiency. *//* Detailed source-code truncated for AI context efficiency. */NOTE: the example above could also have implemented an
ArrayFieldItemButtonsTemplatefor thebuttonPropsrelated code.
Potential BREAKING CHANGE
This template was also updated to support the new Optional Data Controls feature by adding a new optionalDataControl prop to the ArrayFieldTemplateProps interface.
If you have your own implementation of ArrayFieldTemplate and want to support this new feature, please refer to any of the ArrayFieldTemplate implementation for whatever theme you are using and pick up the changes.
ArrayFieldTitleTemplate POTENTIAL BREAKING CHANGE
This template was updated to support the new Optional Data Controls feature by adding a new optionalDataControl prop to the ArrayFieldTitleProps interface.
If you have your own implementation of ArrayFieldTitleTemplate and want to support this new feature, please refer to the ArrayFieldTitleTemplate implementation for @rjsf/core or whatever theme you are using and pick up the 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.
ObjectFieldTemplate POTENTIAL BREAKING CHANGE
This template was updated to support the new Optional Data Controls feature by adding a new optionalDataControl prop to the ObjectFieldTemplateProps interface.
If you have your own implementation of ObjectFieldTemplate and want to support this new feature, please refer to the ObjectFieldTemplate implementation for whatever theme you are using and pick up the changes.
OptionalDataControlsTemplate POTENTIAL BREAKING CHANGE
This new template was created to support the new Optional Data Controls feature.
If you are implementing your own theme you may need to add this new template if you anticipate supporting this new feature.
TitleFieldTemplate POTENTIAL BREAKING CHANGE
This template was updated to support the new Optional Data Controls feature by adding a new optionalDataControl prop to the TitleFieldProps interface.
If you have your own implementation of TitleFieldTemplate and want to support this new feature, please refer to the TitleFieldTemplate implementation for whatever theme you are using and pick up the changes.
SchemaField - Addition of FallbackField POTENTIAL BREAKING CHANGE
The SchemaField was updated to use the new FallbackField, which adds opt-in support to replace the UnsupportedField with an interactive UI instead of an error message.
If you have your own implementation of SchemaField and want to support this new feature, please refer to the SchemaField implementation in @rjsf/core and pick up the changes.
The UnsupportedField component is unaffected by these changes, and is still used by the new FallbackField.
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;
In addition the toIdSchema() function was removed on this type in concert with the toIdSchema() function removal, so update your implementation to remove this as well.
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.
Optional array defaulting (POTENTIAL)
A bug fix was implemented that changes how optional arrays are initialized during the formData defaulting phase.
Previous (buggy) behavior: Optional arrays were initialized to [].
New (correct) behavior: Optional arrays are no longer initialized.
Impact: If your application was incorrectly relying on optional arrays being initialized this way, you may need to update it to handle the corrected behavior.
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 theFieldTemplate. 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 theMultiSchemaField 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 therjsf- 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:
ArrayFieldItemTemplateProps: The properties of each element in the ArrayFieldTemplateProps.items array.ContainerFieldTemplateProps: The common properties of the two container templates:ArrayFieldTemplatePropsandObjectFieldTemplatePropsFallbackFieldProps: The properties passed to the newFallbackFieldcomponentFallbackFieldTemplate: The properties passed to the newFallbackFieldTemplatecomponentFieldPathList- The list of path elements that represents where in the schema a field is locatedFieldPathId- Type describing an id and path used for a fieldFoundFieldType: The interface for the return value of thefindFieldInSchemafunctionGlobalFormOptions: The set of options from theFormthat will be available on theRegistryfor use in everywhere theregistryis available.GridTemplateProps: The properties that are passed to aGridTemplateMultiSchemaFieldTemplateProps: The properties that are passed to aMultiSchemaFieldTemplateOptionalDataControlsTemplateProps: The properties that are passed to a OptionalDataControlsTemplate implementationTestIdShape: The interface for the test ID proxy objects that are returned by thegetTestIdutility function
New non-validator utility functions
Many new or formerly internally private utility functions are available in @rjsf/utils:
buttonId(id: FieldPathId | 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 anobjectand returns the hash of the resulting stringhashString(string: string): string: Hashes a string into hex formatisFormDataAvailable<T = any>(formData?: T)<T = any>(formData?: T): boolean: Determines whether the givenformDatarepresents valid form data, such as a primitive type, an array, or a non-empty objectisRootSchema<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(registry: Registry<T, S, F>, schemaToCompare: S): boolean: Helper to check whether a JSON schema object is the root schemalookupFromFormContext<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 withtoLookupoptionalControlsId(id: FieldPathId | string, element: 'Add' | 'Msg' | 'Remove'): Return a consistentidfor the optional data controlselementshouldRenderOptionalField<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(registry: Registry<T, S, F>, schema: S, required: boolean, uiSchema?: UiSchema<T, S, F>): boolean: Determines if this field should be rendered with the Optional Data Controls UIsortedJSONStringify(object: unknown): string: Stringifies anobject, sorts object fields in consistent order before stringifying ittoFieldPathId(fieldPath: string | number, globalFormOptions: GlobalFormOptions, parentPath?: FieldPathId | FieldPathList, isMultiValue?: boolean): Constructs theFieldPathIdforfieldPathand the optionalparentPath, usingglobalFormOptionsuseAltDateWidgetProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any>(props: WidgetProps<T, S, F>): UseAltDateWidgetResult: which encapsulates the logic needed to render anAltDateWidgetwith optionaltimeelementsuseDeepCompareMemo<T = unknown>(newValue: T): T: Hook that stores and returns aTvalue. IfnewValueis the same as the stored one, then the stored one is returned, otherwisenewValueis stored and returneduseFileWidgetProps(value: string | string[] | undefined | null, onChange: (value?: string | null | (string | null)[]) => void, multiple?: boolean): UseFileWidgetPropsResult: Hook which encapsulates the logic needed to read and convert avalueofFileorFile[]into the props needed by aFileWidgetimplementation.
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 thepathwithin the root or recursedschemafindSelectedOptionInXxxOf<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 theschemaor 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: Reads the value atpathwithin a schema, additionally retrieving$refs as needed to resolve schemas
Changes to existing utility functions
getDefaultFormState(): Added an optionalinitialDefaultsGeneratedboolean flag that indicates whether or not initial defaults have been generatedretrieveSchema(): Added an optionalresolveAnyOfOrOneOfRefsboolean flag that causes the internalresolveAllSchemas()to resolve$refs inside of the options ofanyOf/oneOfschemas- This new optional flag was added to the
SchemaUtilsTypeinterface's version ofretrieveSchema()as well.
- This new optional flag was added to the
validationDataMerge(): Added optionalpreventDuplicatesboolean flag that causes themergeObjects()call to receivepreventDuplicatesinstead oftrue
initialFormData prop added to Form
A new initialFormData prop was added to Form to support providing initial values for an "uncontrolled" React component.
As a result, a small change was made so that formData now causes the Form to behave as a "controlled" React component.
The programmatic reset() will ensure that an "uncontrolled" form is reset back to the initialFormData values when triggered.
setFieldValue() added to Form
A new programmatic function, setFieldValue(fieldPath: string | FieldPathList, newValue?: T): void was added to the Form.
It allows a user to set a value for the provided fieldPath, which must be either a dotted path to the field OR a FieldPathList.
To set the root element, used either '' or [] for the path. Passing undefined will clear the value in the field.
liveValidate and liveOmit performance improvement
Because liveValidate and liveOmit can have serious performance impacts in the Form, those flags were updated to add the following new options:
- 'onChange' - Live validate and live omit will happen as part of the
onChangeprocess