Skip to Content
CustomizeModel UIDeposit form components

Deposit Form Components

This page documents the form components available for customizing record deposit forms. For search result components, see Search result components.

Field Metadata

Field metadata (labels, hints, required status) is defined directly in your model YAML files, not passed as props manually. During model compilation, metadata is extracted and made available through React hooks.

When creating custom field components, use the useFieldData hook:

ui/mymodel/semantic-ui/js/mymodel/forms/CustomField.jsx
import { TextField as InvenioTextField } from "react-invenio-forms"; import { useFieldData } from "@js/oarepo_ui/forms"; export const CustomField = ({ fieldPath, icon, ...rest }) => { const { getFieldData } = useFieldData(); return ( <InvenioTextField optimized fieldPath={fieldPath} {...getFieldData({ fieldPath, icon })} {...rest} /> ); };

Important: Rules of Hooks

The content returned by getFieldData is memoized. Call this function only at the top level of your component to avoid breaking React’s rules of hooks:

✅ Good - At component top level:

const MyForm = () => { const { getFieldData } = useFieldData(); const field1Metadata = getFieldData({ fieldPath: "metadata.name" }); const field2Metadata = getFieldData({ fieldPath: "metadata.value" }); return /* ... */; };

❌ Bad - Inside loops or conditionals:

{items.map((item) => ( <Field key={item.id} metadata={getFieldData({ fieldPath: item.fieldPath })} /> ))}

Available Input Components

Basic Text Input

import { TextField } from "@js/oarepo_ui/forms"; <TextField fieldPath="metadata.title" />
PropTypeDefaultDescription
fieldPathstring(required)Path to the field in dot notation
fieldRepresentationstring”full""full”, “compact”, or “text”
iconstring""Icon to display
...restany-Passed to InvenioTextField

Automatically applies field metadata, XSS protection, and Formik integration.

String Array Input

For fields that contain an array of strings:

import { StringArrayField } from "@js/oarepo_ui/forms"; <StringArrayField fieldPath="metadata.tags" />
PropTypeDefaultDescription
fieldPathstring(required)Path to the field
labelstring|node(from model)Custom label
addButtonLabelstring|node”Add”Button label text
helpTextstring""Help/instruction text
defaultNewValuestring""Default value for new items
requiredboolean(from model)Required status
showEmptyValuebooleanfalseShow empty value on mount
fieldRepresentationstring”text”Field representation style
iconstring(from model)Icon to display

Rich Text Editor

Uses TinyMCE for formatted text input:

import { RichInputField } from "react-invenio-forms"; import { OarepoRichEditor } from "@js/oarepo_ui/forms"; <RichInputField fieldPath="metadata.description" label="Description" editor={<OarepoRichEditor />} />

Note: Unlike most components, RichInputField requires explicit field metadata props.

Date Pickers (EDTF)

Support for Extended Date/Time Format with precision options:

import { EDTFSingleDatePickerField, EDTFDateRangePickerField, } from "@js/oarepo_ui/forms"; // Single date <EDTFSingleDatePickerField fieldPath="metadata.publicationDate" /> // Date range <EDTFDateRangePickerField fieldPath="metadata.eventDateRange" />

Common props (both components):

PropTypeDefaultDescription
fieldPathstring(required)Path to the field
labelstring|node(from model)Custom label
iconstring”calendar”Icon to display
requiredboolean(from model)Required status
helpTextstring(from model)Help text to display

EDTFSingleDatePickerField specific props:

PropTypeDefaultDescription
placeholderstring(from model)Placeholder text
datePickerPropsobjectProps for underlying date picker
customInputPropsobjectProps for custom input element

EDTFDateRangePickerField specific props:

PropTypeDefaultDescription
dateRangeInputPlaceholderstring”Choose date range (From - To).”Placeholder for range mode
singleDateInputPlaceholderstring”Choose one date.”Placeholder for single date mode
datePickerPropsOverridesobjectOverride picker behavior

Multilingual Inputs

For content in multiple languages:

import { I18nTextInputField, I18nRichInputField, } from "@js/oarepo_ui/forms"; // Plain text <I18nTextInputField fieldPath="metadata.multilingualTitle" /> // Rich text <I18nRichInputField fieldPath="metadata.multilingualDescription" />

Data format:

multilingual_field_data.json
{ "lang": "en", "value": "Title in English" }

Common props (both components):

PropTypeDefaultDescription
fieldPathstring(required)Path to the field
lngFieldWidthnumber3Language selector width (1-16)
optimizedbooleantrueOptimized rendering
usedLanguagesarray[]Languages already in use

I18nRichInputField additional props:

PropTypeDefaultDescription
editorConfigobjectConfiguration for rich text editor

Vocabulary Selection

For controlled terminology dropdowns:

import { LocalVocabularySelectField, VocabularySelectField, } from "@js/oarepo_vocabularies/form"; // Pre-loaded local vocabulary (from formConfig) <LocalVocabularySelectField fieldPath="metadata.resourceType" vocabularyName="resource-types" /> // API-loaded vocabulary <VocabularySelectField fieldPath="metadata.subjects" vocabularyName="subjects" multiple={true} />

Common props (both components):

PropTypeDefaultDescription
fieldPathstring(required)Path to the field
vocabularyNamestring(required)Vocabulary name
multipleboolean(from model)Allow multiple selections
clearablebooleantrueAllow clearing selection
showLeafsOnlybooleanfalseShow only leaf nodes in hierarchies
filterFunctionfunc(opt) => optFilter function for options
iconstring”tag” / (from model)Icon to display

LocalVocabularySelectField - Best for small vocabularies loaded all at once:

PropTypeDefaultDescription
optimizedbooleantrueOptimized rendering
usedOptionsarray[]Options already in use elsewhere

VocabularySelectField - For large vocabularies loaded via API:

PropTypeDefaultDescription
externalAuthoritybooleanfalseExternal authority mode
suggestionAPIHeadersobject”see above”API headers for suggestions

Complex Nested Fields

For arrays of nested fields:

ui/mymodel/semantic-ui/js/mymodel/forms/EventsField.jsx
import React from "react"; import { ArrayField, GroupField } from "react-invenio-forms"; import { LocalVocabularySelectField } from "@js/oarepo_vocabularies/form"; import { TextField, StringArrayField, EDTFDateRangePickerField, } from "@js/oarepo_ui/forms"; import { useFieldData } from "@js/oarepo_ui/forms"; export const EventsField = ({ fieldPath }) => { const { getFieldData } = useFieldData(); return ( <ArrayField addButtonLabel="Add event" fieldPath={fieldPath} {...getFieldData({ fieldPath, fieldRepresentation: "text" })} > {({ indexPath }) => { const prefix = `${fieldPath}.${indexPath}`; return ( <> <TextField fieldPath={`${prefix}.eventName`} /> <EDTFDateRangePickerField fieldPath={`${prefix}.eventDate`} /> <GroupField> <TextField fieldPath={`${prefix}.location.place`} /> <LocalVocabularySelectField fieldPath={`${prefix}.location.country`} vocabularyName="countries" /> </GroupField> </> ); }} </ArrayField> ); };

Fields in Modal

For very complex fields, consider using a modal for better UX. This requires an internal Formik instance to manage the modal form.

Example: Creatibutors field  from RDM.

Trade-offs:

  • Use modals only when truly necessary
  • Requires data conversion between main form and modal
  • Can be challenging with deeply nested data
Last updated on