A React component that automatically generates interactive web forms from JSON Schema definitions.
—
Template components control how form elements are displayed and styled. They provide the layout structure, styling, and presentation logic for fields, errors, arrays, buttons, and other form elements.
Built-in template components that control form layout and presentation.
interface TemplatesType<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** Template for array field descriptions */
ArrayFieldDescriptionTemplate: ComponentType<ArrayFieldDescriptionProps<T, S, F>>;
/** Template for individual array items with controls */
ArrayFieldItemTemplate: ComponentType<ArrayFieldTemplateItemType<T, S, F>>;
/** Template for entire array fields with add/remove controls */
ArrayFieldTemplate: ComponentType<ArrayFieldTemplateProps<T, S, F>>;
/** Template for array field titles and headers */
ArrayFieldTitleTemplate: ComponentType<ArrayFieldTitleProps<T, S, F>>;
/** Base template for input widgets with common styling */
BaseInputTemplate: ComponentType<BaseInputTemplateProps<T, S, F>>;
/** Template for field descriptions and help text */
DescriptionFieldTemplate: ComponentType<DescriptionFieldProps<T, S, F>>;
/** Template for error list display at form level */
ErrorListTemplate: ComponentType<ErrorListProps<T, S, F>>;
/** Template for individual form fields with labels and errors */
FieldTemplate: ComponentType<FieldTemplateProps<T, S, F>>;
/** Template for field-specific error messages */
FieldErrorTemplate: ComponentType<FieldErrorProps<T, S, F>>;
/** Template for field help text display */
FieldHelpTemplate: ComponentType<FieldHelpProps<T, S, F>>;
/** Template for object fields with property layout */
ObjectFieldTemplate: ComponentType<ObjectFieldTemplateProps<T, S, F>>;
/** Template for field titles and labels */
TitleFieldTemplate: ComponentType<TitleFieldProps<T, S, F>>;
/** Template for unsupported field types fallback */
UnsupportedFieldTemplate: ComponentType<UnsupportedFieldProps<T, S, F>>;
/** Template for additional properties wrapper */
WrapIfAdditionalTemplate: ComponentType<WrapIfAdditionalTemplateProps<T, S, F>>;
/** Collection of button templates for form actions */
ButtonTemplates: {
/** Form submit button */
SubmitButton: ComponentType<SubmitButtonProps<T, S, F>>;
/** Add array item button */
AddButton: ComponentType<IconButtonProps<T, S, F>>;
/** Copy array item button */
CopyButton: ComponentType<IconButtonProps<T, S, F>>;
/** Move array item down button */
MoveDownButton: ComponentType<IconButtonProps<T, S, F>>;
/** Move array item up button */
MoveUpButton: ComponentType<IconButtonProps<T, S, F>>;
/** Remove array item button */
RemoveButton: ComponentType<IconButtonProps<T, S, F>>;
};
}Main template for individual form fields, controls layout of labels, inputs, errors, and help text.
/**
* Main template for individual form fields
* Handles label, input, error, and help text layout
*/
interface FieldTemplateProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** Field ID for accessibility */
id: string;
/** CSS class names */
classNames: string;
/** Field label text */
label?: string;
/** Whether to display the label */
displayLabel: boolean;
/** Field description text */
description?: React.ReactNode;
/** Raw description from schema */
rawDescription?: string;
/** Field help text */
help?: React.ReactNode;
/** Raw help text */
rawHelp?: string;
/** Field error messages */
errors?: React.ReactNode;
/** Raw error messages */
rawErrors?: string[];
/** Whether field is required */
required: boolean;
/** Whether field is hidden */
hidden: boolean;
/** Whether field is readonly */
readonly: boolean;
/** Whether field is disabled */
disabled: boolean;
/** Form registry */
registry: Registry<T, S, F>;
/** Form context */
formContext: F;
/** Field children (widget) */
children: React.ReactNode;
/** JSON schema */
schema: S;
/** UI schema */
uiSchema: UiSchema<T, S, F>;
/** Form data */
formData: T;
}
const FieldTemplate: ComponentType<FieldTemplateProps<T, S, F>>;Usage Examples:
// Custom field template with Bootstrap styling
const BootstrapFieldTemplate = (props: FieldTemplateProps) => {
const {
id,
classNames,
label,
children,
errors,
help,
description,
hidden,
required,
displayLabel,
} = props;
if (hidden) {
return <div className="hidden">{children}</div>;
}
return (
<div className={`form-group ${classNames}`}>
{displayLabel && label && (
<label htmlFor={id} className="control-label">
{label}
{required && <span className="text-danger"> *</span>}
</label>
)}
{description && (
<div className="field-description text-muted">{description}</div>
)}
{children}
{errors && <div className="text-danger">{errors}</div>}
{help && <small className="form-text text-muted">{help}</small>}
</div>
);
};Template for object fields that contain multiple properties.
/**
* Template for object fields with multiple properties
* Handles property layout and additional properties
*/
interface ObjectFieldTemplateProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** Object field ID */
id: string;
/** CSS class names */
classNames: string;
/** Object field title */
title?: string;
/** Object field description */
description?: React.ReactNode;
/** Whether title should be displayed */
displayTitle: boolean;
/** Array of property elements */
properties: ObjectFieldTemplatePropertyType[];
/** Whether object is required */
required: boolean;
/** Whether object is readonly */
readonly: boolean;
/** Whether object is disabled */
disabled: boolean;
/** Form registry */
registry: Registry<T, S, F>;
/** Form context */
formContext: F;
/** JSON schema */
schema: S;
/** UI schema */
uiSchema: UiSchema<T, S, F>;
/** Form data */
formData: T;
}
interface ObjectFieldTemplatePropertyType {
content: React.ReactElement;
name: string;
readonly: boolean;
disabled: boolean;
required: boolean;
}
const ObjectFieldTemplate: ComponentType<ObjectFieldTemplateProps<T, S, F>>;Custom Implementation:
const CustomObjectFieldTemplate = (props: ObjectFieldTemplateProps) => {
const { title, properties, description, displayTitle } = props;
return (
<fieldset className="object-field">
{displayTitle && title && <legend>{title}</legend>}
{description && <div className="object-description">{description}</div>}
<div className="object-properties">
{properties.map((prop, index) => (
<div key={index} className={`property ${prop.name}`}>
{prop.content}
</div>
))}
</div>
</fieldset>
);
};Base template for input widgets with common styling and structure.
/**
* Base template for input widgets
* Provides common structure for form inputs
*/
interface BaseInputTemplateProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** Input ID */
id: string;
/** Input value */
value: any;
/** Input label */
label: string;
/** Input type */
type: string;
/** Placeholder text */
placeholder?: string;
/** Whether input is required */
required: boolean;
/** Whether input is disabled */
disabled: boolean;
/** Whether input is readonly */
readonly: boolean;
/** Whether input should autofocus */
autofocus: boolean;
/** Change handler */
onChange: (value: any) => void;
/** Blur handler */
onBlur: (id: string, value: any) => void;
/** Focus handler */
onFocus: (id: string, value: any) => void;
/** Additional options */
options: any;
/** JSON schema */
schema: S;
/** UI schema */
uiSchema: UiSchema<T, S, F>;
/** Form context */
formContext: F;
/** Form registry */
registry: Registry<T, S, F>;
/** Raw validation errors */
rawErrors?: string[];
}
const BaseInputTemplate: ComponentType<BaseInputTemplateProps<T, S, F>>;Main template for array fields with item management controls.
/**
* Template for array fields with add/remove/reorder controls
* Manages array items and provides action buttons
*/
interface ArrayFieldTemplateProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** Array field ID */
id: string;
/** CSS class names */
classNames: string;
/** Array field title */
title?: string;
/** Array field description */
description?: React.ReactNode;
/** Array items */
items: ArrayFieldTemplateItemType<T, S, F>[];
/** Whether items can be added */
canAdd: boolean;
/** Add item handler */
onAddClick: (event: React.MouseEvent) => void;
/** Whether array is disabled */
disabled: boolean;
/** Whether array is readonly */
readonly: boolean;
/** Form registry */
registry: Registry<T, S, F>;
/** Form context */
formContext: F;
/** JSON schema */
schema: S;
/** UI schema */
uiSchema: UiSchema<T, S, F>;
/** Form data */
formData: T[];
}
interface ArrayFieldTemplateItemType<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** Item content */
children: React.ReactElement;
/** Item index */
index: number;
/** Whether item can be removed */
hasRemove: boolean;
/** Whether item can be moved up */
hasMoveUp: boolean;
/** Whether item can be moved down */
hasMoveDown: boolean;
/** Whether item can be copied */
hasCopy: boolean;
/** Remove item handler */
onDropIndexClick: (index: number) => (event: React.MouseEvent) => void;
/** Move up handler */
onReorderClick: (index: number, newIndex: number) => (event: React.MouseEvent) => void;
/** Copy item handler */
onCopyIndexClick: (index: number) => (event: React.MouseEvent) => void;
/** Whether item is readonly */
readonly: boolean;
/** Whether item is disabled */
disabled: boolean;
}
const ArrayFieldTemplate: ComponentType<ArrayFieldTemplateProps<T, S, F>>;Custom Array Template:
const CustomArrayFieldTemplate = (props: ArrayFieldTemplateProps) => {
const {
items,
canAdd,
onAddClick,
title,
description,
registry
} = props;
const { AddButton } = registry.templates.ButtonTemplates;
return (
<div className="array-field">
{title && <h3>{title}</h3>}
{description && <div className="array-description">{description}</div>}
<div className="array-items">
{items.map((item, index) => (
<div key={index} className="array-item">
<div className="item-content">{item.children}</div>
<div className="item-controls">
{item.hasRemove && (
<button onClick={item.onDropIndexClick(item.index)}>
Remove
</button>
)}
{item.hasMoveUp && (
<button onClick={item.onReorderClick(item.index, item.index - 1)}>
Move Up
</button>
)}
{item.hasMoveDown && (
<button onClick={item.onReorderClick(item.index, item.index + 1)}>
Move Down
</button>
)}
</div>
</div>
))}
</div>
{canAdd && (
<div className="array-add">
<AddButton onClick={onAddClick} />
</div>
)}
</div>
);
};Template for individual array items with controls.
/**
* Template for individual array items
* Wraps item content with controls
*/
const ArrayFieldItemTemplate: ComponentType<ArrayFieldTemplateItemType<T, S, F>>;Template for displaying form-level errors.
/**
* Template for form-level error list display
* Shows validation errors at top or bottom of form
*/
interface ErrorListProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** Array of validation errors */
errors: RJSFValidationError[];
/** Form registry */
registry: Registry<T, S, F>;
/** Form context */
formContext: F;
/** JSON schema */
schema: S;
/** UI schema */
uiSchema: UiSchema<T, S, F>;
}
const ErrorListTemplate: ComponentType<ErrorListProps<T, S, F>>;Template for field-specific error messages.
/**
* Template for field-specific error messages
* Displays errors inline with fields
*/
interface FieldErrorProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** Array of error messages */
errors: string[];
/** Field ID */
idSchema: IdSchema<T>;
/** JSON schema */
schema: S;
/** UI schema */
uiSchema: UiSchema<T, S, F>;
/** Form registry */
registry: Registry<T, S, F>;
}
const FieldErrorTemplate: ComponentType<FieldErrorProps<T, S, F>>;Template for field help text display.
/**
* Template for field help text display
* Shows guidance and instructions for fields
*/
interface FieldHelpProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** Help text content */
help: React.ReactNode;
/** Field ID */
idSchema: IdSchema<T>;
/** JSON schema */
schema: S;
/** UI schema */
uiSchema: UiSchema<T, S, F>;
/** Form registry */
registry: Registry<T, S, F>;
}
const FieldHelpTemplate: ComponentType<FieldHelpProps<T, S, F>>;Collection of button templates for form actions.
interface ButtonTemplates<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** Form submit button */
SubmitButton: ComponentType<SubmitButtonProps<T, S, F>>;
/** Add array item button */
AddButton: ComponentType<IconButtonProps<T, S, F>>;
/** Copy array item button */
CopyButton: ComponentType<IconButtonProps<T, S, F>>;
/** Move array item down button */
MoveDownButton: ComponentType<IconButtonProps<T, S, F>>;
/** Move array item up button */
MoveUpButton: ComponentType<IconButtonProps<T, S, F>>;
/** Remove array item button */
RemoveButton: ComponentType<IconButtonProps<T, S, F>>;
}Template for form submit button.
/**
* Template for form submit button
* Handles form submission trigger
*/
interface SubmitButtonProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** UI schema submit button options */
uiSchema: UiSchema<T, S, F>;
/** Form registry */
registry: Registry<T, S, F>;
/** Form context */
formContext: F;
/** Whether form is disabled */
disabled: boolean;
/** Whether form is readonly */
readonly: boolean;
}
const SubmitButton: ComponentType<SubmitButtonProps<T, S, F>>;Common props for array action buttons.
interface IconButtonProps<T = any, S extends StrictRJSFSchema = RJSFSchema, F extends FormContextType = any> {
/** Button icon name or element */
icon?: string | React.ReactElement;
/** Button color scheme */
color?: string;
/** Button title/tooltip */
title?: string;
/** CSS class names */
className?: string;
/** Tab index */
tabIndex?: number;
/** Whether button is disabled */
disabled?: boolean;
/** Click handler */
onClick?: (event: React.MouseEvent) => void;
/** UI schema */
uiSchema?: UiSchema<T, S, F>;
/** Form registry */
registry?: Registry<T, S, F>;
}const MaterialFieldTemplate = (props: FieldTemplateProps) => {
const {
id,
label,
children,
errors,
help,
description,
required,
displayLabel,
hidden
} = props;
if (hidden) {
return <div style={{ display: 'none' }}>{children}</div>;
}
return (
<div className="material-field">
{displayLabel && label && (
<label htmlFor={id} className="material-label">
{label}
{required && <span className="required">*</span>}
</label>
)}
<div className="material-input-container">
{children}
</div>
{description && (
<div className="material-description">{description}</div>
)}
{errors && (
<div className="material-errors">{errors}</div>
)}
{help && (
<div className="material-help">{help}</div>
)}
</div>
);
};const CustomButtonTemplates = {
SubmitButton: (props: SubmitButtonProps) => (
<button type="submit" className="btn btn-primary">
Submit Form
</button>
),
AddButton: (props: IconButtonProps) => (
<button
type="button"
className="btn btn-success btn-sm"
onClick={props.onClick}
disabled={props.disabled}
title="Add Item"
>
+ Add
</button>
),
RemoveButton: (props: IconButtonProps) => (
<button
type="button"
className="btn btn-danger btn-sm"
onClick={props.onClick}
disabled={props.disabled}
title="Remove Item"
>
× Remove
</button>
)
};
// Use custom templates
const customTemplates = {
FieldTemplate: MaterialFieldTemplate,
ButtonTemplates: CustomButtonTemplates
};
<Form
schema={schema}
validator={validator}
templates={customTemplates}
/>Install with Tessl CLI
npx tessl i tessl/npm-rjsf--core