React JSON Schema Form (RJSF)
repository·main·Indexed 12 days ago
https://github.com/rjsf-team/react-jsonschema-formA React-based library for the declarative creation of web forms using JSON Schema. It is highly extensible via pluggable validators and theme-specific packages, including support for Ant Design (@rjsf/antd), Chakra UI (@rjsf/chakra-ui), DaisyUI (@rjsf/daisyui), Fluent UI (@rjsf/fluentui-rc), Mantine (@rjsf/mantine), and a core Bootstrap 3 theme (@rjsf/core).
What's inside React JSON Schema Form
- react-jsonschema-form is a React component that uses JSON Schema to declaratively build and customize web forms. It allows developers to define form structures using standard JSON Schema and automatically generates the corresponding UI components.
Understand the DaisyUI testing strategy
mainThe DaisyUI theme testing strategy is divided into three main layers to ensure functional correctness, UI fidelity, and accessibility:
- Core Snapshot Tests: Validates the overall form rendering, array fields, and object fields using the shared RJSF snapshot infrastructure.
- DaisyUI-Specific Component Tests: Unit tests for components unique to this theme, such as:
DaisyUIFrameProvider: Verifies iframe theme injection.ToggleWidget: Tests the toggle component interaction.RatingWidget: Tests the rating component interaction.ArrayFieldItemTemplate: Tests the card-based UI used for array items.
- Helper Functions: Uses
createMocks.tsto generate mock props for form components.
Coverage Areas include:
- Functional: Widget interaction (toggles, ratings), form validation, and data binding.
- UI: Application of DaisyUI CSS classes, responsive layouts, and theme application.
- Accessibility: Keyboard navigation, ARIA attributes, and focus management.
- Theme Management: Theme switching and persistence in
localStorage.
Use @rjsf/validator-ata as an alternative to AJV
mainThe
@rjsf/validator-atapackage is an alternative validation engine for React JSON Schema Form, powered byata-validatorinstead of AJV.Because its public API mirrors
@rjsf/validator-ajv8, you can often swap the validator by simply changing your imports. It supports the same core customization patterns includingcustomizeValidator(),ValidatorType, custom formats,transformErrors,customValidate, andsuppressDuplicateFiltering.Key Differences from AJV:
- Options: Instead of
ajvOptionsOverrides, useataOptionsOverridesto pass options directly toata-validator(e.g.,coerceTypes,removeAdditional,verbose,abortEarly). - Formats: The
ata-validatorformat set is always installed; there is no opt-in flag. - Error Handling:
ata-validatorerror parameters are frozen, so a pre-quote pass for i18n is not required, though localizers that mutate themessageproperty still work.
- Options: Instead of
What is a uiSchema?
mainWhile JSON Schema defines what data the form should contain, the
uiSchemadefines how that data should be rendered. It is an object literal that follows the tree structure of the form field hierarchy, providing instructions for UI components (widgets, fields, styles, etc.).Most properties in a
uiSchemacan be defined in two equivalent ways:- Using a direct
ui:[property]key. - Using a nested
ui:optionsobject.
Example of equivalence:
// Option 1: Direct { "ui:title": "Title", "ui:classNames": "my-class" } // Option 2: Nested { "ui:options": { "title": "Title", "classNames": "my-class" } }{ "ui:title": "Title", "ui:description": "Description", "ui:classNames": "my-class", "ui:submitButtonOptions": { "props": { "disabled": false, "className": "btn btn-info" }, "norender": false, "submitText": "Submit" } }- Using a direct
Configure ui:row for grid layouts
mainThe
ui:rowis the outermost level of aLayoutGridField. It defines nested rows, columns, or conditional elements. It can be defined in two ways:- Simple definition: An array of "grid elements" (e.g.,
ui:col,ui:row,ui:columns, orui:condition). - Complex definition: An object containing native
GridTemplateimplementation-specific props (likespacing,size,className, etc.) and achildrenarray of grid elements.
Note on
className: AllclassNamevalues are automatically looked up in theformContext.lookupMapif they are defined using a CSS-in-JS approach. If multiple classes are provided (e.g.,'GridRow GridColumn'), they are split, looked up individually, and rejoined.{ "ui:row": [ { "ui:row"|"ui:col"|"ui:columns"|"ui:condition": ... }, ... ] } // Complex example with MUI Grid2 props { "ui:row": { "spacing": 2, "size": { "md": 4 }, "alignContent": "flex-start", "className": "GridRow", "children": [ { "ui:row"|"ui:col"|"ui:columns"|"ui:condition": ... } ] } }- Simple definition: An array of "grid elements" (e.g.,
Use @rjsf/validator-cfworker for CSP-constrained applications
mainUse
@rjsf/validator-cfworkerwhen your application is subject to strict Content Security Policy (CSP) constraints that forbid the use ofevalornew Function.Unlike the default
@rjsf/validator-ajv8, this validator is backed by@cfworker/json-schemaand interprets schemas without using prohibited JavaScript execution patterns. It defaults to JSON Schema draft2020-12.Important Limitations:
- It is not a direct replacement for AJV. It does not support AJV-specific options or extensions like
AjvClass,$data,discriminator, orajv-errors'serrorMessage. $dynamicRefand$dynamicAnchorare not supported.- Error messages differ from AJV, and there is no
ajv-i18nequivalent. To customize error messages, use thetransformErrorsprop in RJSF. - Precompiled-validator mode is not supported.
- It is not a direct replacement for AJV. It does not support AJV-specific options or extensions like
Understand the difference between Custom Fields, Custom Templates, and Custom Widgets
mainWhen customizing React JSON Schema Form (RJSF), you can choose between three levels of abstraction depending on how much behavior you want to override:
- Custom Field: Overrides all behavior (layout, labels, help, validation, and the input itself). Can be applied globally or per-field.
- Custom Template: Overrides just the layout (e.g., how an array of items is wrapped or how a field is structured), but does not change the underlying behavior or input logic. Can be applied globally or per-field.
- Custom Widget: Overrides just the input box (the actual interactive element), but does not change the layout, labels, help text, or validation. Can be applied globally or per-field.
Usage Patterns
Global Application (via the
Formcomponent):- Fields:
<Form fields={{ MyCustomField }} /> - Templates:
<Form templates={{ ArrayFieldTemplate: MyArrayTemplate }} /> - Widgets:
<Form widgets={{ MyCustomWidget }} />
Per-Field Application (via the
uiSchema):- Fields:
"ui:field": MyCustomField - Templates:
"ui:ArrayFieldTemplate": MyArrayTemplate - Widgets:
"ui:widget": MyCustomWidget
// Global Example <Form schema={schema} uiSchema={uiSchema} templates={{ ArrayFieldTemplate: MyArrayTemplate }} widgets={{ MyCustomWidget }} fields={{ MyCustomField }} /> // Per-Field Example (uiSchema) const uiSchema = { myField: { "ui:field": MyCustomField, "ui:ArrayFieldTemplate": MyArrayTemplate, "ui:widget": MyCustomWidget } };Understand the difference between slotProps and rjsfSlotProps in @rjsf/mui
main@rjsf/muiuses two distinct keys for slot customization to prevent 'prop bleeding' (accidentally passing configuration to unintended child components):slotProps: Used for standard MUI customization. These are passed directly to MUI's nativeslotPropsAPI on a component (e.g., targetinghtmlInput,input, orinputLabelon aTextField).rjsfSlotProps: Used specifically for RJSF template components (likeArrayFieldTemplateorObjectFieldTemplate). This key targets RJSF-specific sub-components (likepaper,grid, orbox) and is explicitly extracted by the library.
/* Example of slotProps for a MUI widget */ { "myPriceField": { "ui:options": { "mui": { "slotProps": { "input": { "startAdornment": "$" } } } } } } /* Example of rjsfSlotProps for a structural template */ { "myArrayField": { "ui:options": { "mui": { "rjsfSlotProps": { "arrayPaper": { "elevation": 10 } } } } } }Configure ui:col for columns
mainThe
ui:colelement specifies columns within aui:row. It supports several formats:- Simple list: An array of dotted-path field names (e.g.,
["field1", "field2.subfield"]). - Object list: An array of objects containing a
name(dotted-path) and other props that are gathered intoui:options. - Custom render: An array containing a one-off functional component. If a
nameis provided, it maps to a field; otherwise, it's treated as a custom component. Ifrenderis a string, it is looked up informContext.lookupMap. - Complex object: An object with native
GridTemplateprops and achildrenarray containing any of the above types.
Fallback behavior: If a
namedoes not match a schema field, it is assumed to be a customrendercomponent. Ifrenderis missing, it results in a null render.{ "ui:col": ["innerField", "inner.grandChild"] } { "ui:col": [ { "name": "innerField", "fullWidth": true }, { "name": "inner.grandChild", "fullWidth": false } ] } { "ui:col": [ "innerField", { "render": "WizardNavButton", "isNext": true, "size": "large" } ] } { "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": ... } ] } }- Simple list: An array of dotted-path field names (e.g.,
Use allOf in JSON Schema
mainA schema using
allOfis valid only if all of the provided subschemas are valid.Internally,
react-jsonschema-formuses the@x0k/json-schema-mergelibrary to merge the specified subschemas into a single combined subschema. For example, if one subschema requirestype: ['string', 'boolean']and another requirestype: 'boolean', the resulting merged schema will effectively requiretype: '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'));Use ui:columns as syntactic sugar for ui:col
mainThe
ui:columnselement is a shorthand for defining multipleui:colelements that share the same nativeGridTemplateprops. Instead of repeating the same props for every column, you can wrap achildrenarray in a singleui:columnsblock.Difference from
ui:col: Usingui:columnswith achildrenarray renders all those children inside a single<GridTemplate>element with the specified props, whereas multipleui:colelements would each render their own<GridTemplate>element.{ "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"] } } ] } }Handle changes in primitive field and array defaulting
mainTwo bug fixes in v6 change the behavior of data initialization, which may impact applications relying on specific side effects:
- Primitive fields in oneOf/anyOf: When switching between schema variants with
mergeDefaultsIntoFormData: "useDefaultIfFormDataUndefined", undefined primitive fields (boolean, string, number) will now remainundefinedor receive their proper default value, instead of being incorrectly set to an empty object{}. - Optional arrays: Optional arrays are no longer automatically initialized to
[]during theformDatadefaulting phase. They will remain uninitialized if not present in the data.
- Primitive fields in oneOf/anyOf: When switching between schema variants with