A React component that automatically generates interactive web forms from JSON Schema definitions.
—
The Form component is the main React component that renders JSON schemas as interactive forms with validation, customization, and event handling capabilities.
Main form component that converts JSON Schema definitions into interactive React forms.
/**
* Main form component that renders JSON schemas as interactive forms
* @template T - Type of form data
* @template S - Type of JSON schema (extends StrictRJSFSchema)
* @template F - Type of form context (extends FormContextType)
*/
export default class Form<
T = any,
S extends StrictRJSFSchema = RJSFSchema,
F extends FormContextType = any
> extends Component<FormProps<T, S, F>, FormState<T, S, F>> {
/** Programmatically submit the form */
submit(): void;
/** Validate current form data and return whether it's valid */
validateForm(): boolean;
/** Reset form to initial state */
reset(): void;
/** Focus on the field that has the given error */
focusOnError(error: RJSFValidationError): void;
}Usage Examples:
import Form from "@rjsf/core";
import validator from "@rjsf/validator-ajv8";
// Basic form with validation
const MyForm = () => {
const schema = {
type: "object",
properties: {
name: { type: "string", title: "Full Name" },
age: { type: "number", title: "Age", minimum: 0 }
},
required: ["name"]
};
return (
<Form
schema={schema}
validator={validator}
onSubmit={({ formData }) => console.log(formData)}
/>
);
};
// Form with custom validation and error handling
const AdvancedForm = () => {
const [errors, setErrors] = useState([]);
const formRef = useRef<Form>(null);
const customValidate = (formData, errors) => {
if (formData.age < 18) {
errors.age.addError("Must be 18 or older");
}
return errors;
};
const handleSubmit = ({ formData }) => {
if (formRef.current?.validateForm()) {
console.log("Valid form data:", formData);
}
};
return (
<Form
ref={formRef}
schema={schema}
validator={validator}
customValidate={customValidate}
onSubmit={handleSubmit}
onError={setErrors}
showErrorList="top"
/>
);
};Complete configuration interface for the Form component with all available options.
interface FormProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
// Core required props
/** JSON schema object defining the form structure */
schema: S;
/** Validator implementation for form validation */
validator: ValidatorType<T, S, F>;
// Data management
/** UI schema for customizing form appearance and behavior */
uiSchema?: UiSchema<T, S, F>;
/** Initial or current form data */
formData?: T;
/** Context object passed to all fields and widgets */
formContext?: F;
// Form configuration
/** Prefix for form field IDs (default: "root") */
idPrefix?: string;
/** Separator for nested field IDs (default: "_") */
idSeparator?: string;
/** Disable the entire form */
disabled?: boolean;
/** Make the entire form read-only */
readonly?: boolean;
// Registry overrides
/** Custom field components */
fields?: RegistryFieldsType<T, S, F>;
/** Custom widget components */
widgets?: RegistryWidgetsType<T, S, F>;
/** Custom template components */
templates?: Partial<TemplatesType<T, S, F>>;
// Event handlers
/** Called when form data changes */
onChange?: (data: IChangeEvent<T, S, F>, id?: string) => void;
/** Called when validation errors occur */
onError?: (errors: RJSFValidationError[]) => void;
/** Called when form is submitted */
onSubmit?: (data: IChangeEvent<T, S, F>, event: FormEvent<any>) => void;
/** Called when a field loses focus */
onBlur?: (id: string, data: any) => void;
/** Called when a field gains focus */
onFocus?: (id: string, data: any) => void;
// Validation configuration
/** Custom validation function */
customValidate?: CustomValidator<T, S, F>;
/** Additional errors to display */
extraErrors?: ErrorSchema<T>;
/** Whether extra errors should block form submission */
extraErrorsBlockSubmit?: boolean;
/** Disable HTML5 validation */
noHtml5Validate?: boolean;
/** Validate on every change (default: false) */
liveValidate?: boolean;
/** Omit extra data on change events */
liveOmit?: boolean;
/** Omit extra data on form submission */
omitExtraData?: boolean;
/** Where to show error list: false, 'top', or 'bottom' */
showErrorList?: false | 'top' | 'bottom';
/** Transform validation errors before display */
transformErrors?: ErrorTransformer<T, S, F>;
/** Auto-focus first field with error */
focusOnFirstError?: boolean | ((error: RJSFValidationError) => void);
// HTML form attributes
/** Accept-charset HTML attribute */
acceptCharset?: string;
/** Action HTML attribute */
action?: string;
/** Autocomplete HTML attribute */
autoComplete?: string;
/** CSS class name */
className?: string;
/** Enctype HTML attribute */
enctype?: string;
/** HTML id attribute */
id?: string;
/** HTML name attribute */
name?: string;
/** HTTP method */
method?: string;
/** Custom HTML tag (default: 'form') */
tagName?: ElementType;
/** Target HTML attribute */
target?: string;
// Advanced configuration
/** Translation function for internationalization */
translateString?: (str: TranslatableString, params?: string[]) => string;
/** Experimental default form state behavior */
experimental_defaultFormStateBehavior?: Experimental_DefaultFormStateBehavior;
/** Experimental custom allOf merger */
experimental_customMergeAllOf?: Experimental_CustomMergeAllOf<S>;
// Other
/** Custom submit button or form content */
children?: ReactNode;
/** Internal form wrapper component */
_internalFormWrapper?: ElementType;
}Interface representing the internal state of the Form component.
interface FormState<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** Current form data */
formData: T;
/** Current validation errors */
errors: RJSFValidationError[];
/** Current error schema structure */
errorSchema: ErrorSchema<T>;
/** Schema-level validation errors */
schemaValidationErrors: RJSFValidationError[];
/** Schema-level error schema */
schemaValidationErrorSchema: ErrorSchema<T>;
}Interface for form change and submit events.
interface IChangeEvent<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** Current schema */
schema: S;
/** Current UI schema */
uiSchema: UiSchema<T, S, F>;
/** Current ID schema */
idSchema: IdSchema<T>;
/** Schema utilities instance */
schemaUtils: SchemaUtilsType<T, S, F>;
/** Current form data */
formData?: T;
/** Whether form is in edit mode */
edit: boolean;
/** Current validation errors */
errors: RJSFValidationError[];
/** Current error schema */
errorSchema: ErrorSchema<T>;
/** Status when submitted (only present on submit) */
status?: 'submitted';
}import { useRef } from 'react';
import Form from '@rjsf/core';
const FormWithRef = () => {
const formRef = useRef<Form>(null);
const handleCustomSubmit = () => {
// Validate programmatically
if (formRef.current?.validateForm()) {
// Submit programmatically
formRef.current.submit();
}
};
const handleReset = () => {
formRef.current?.reset();
};
return (
<div>
<Form
ref={formRef}
schema={schema}
validator={validator}
onSubmit={handleSubmit}
/>
<button onClick={handleCustomSubmit}>Custom Submit</button>
<button onClick={handleReset}>Reset Form</button>
</div>
);
};const customValidate = (formData, errors, uiSchema) => {
// Cross-field validation
if (formData.password !== formData.confirmPassword) {
errors.confirmPassword.addError("Passwords don't match");
}
// Async validation
if (formData.email) {
validateEmailAsync(formData.email).then(isValid => {
if (!isValid) {
errors.email.addError("Email already exists");
}
});
}
return errors;
};
<Form
schema={schema}
validator={validator}
customValidate={customValidate}
liveValidate={true}
/>const formContext = {
currentUser: user,
theme: 'dark',
readonlyMode: false
};
<Form
schema={schema}
validator={validator}
formContext={formContext}
// Form context is available in all custom fields/widgets
/>const transformErrors = (errors) => {
return errors.map(error => ({
...error,
message: translateError(error.message, currentLocale)
}));
};
<Form
schema={schema}
validator={validator}
transformErrors={transformErrors}
showErrorList="top"
focusOnFirstError={true}
/>Install with Tessl CLI
npx tessl i tessl/npm-rjsf--core