ArrayInput
To edit arrays of data embedded inside a record, <ArrayInput> creates a list of sub-forms.

<ArrayInput> allows editing of embedded arrays, like the items field in the following order record:
{ "id": 1, "date": "2022-08-30", "customer": "John Doe", "items": [ { "name": "Office Jeans", "price": 45.99, "quantity": 1, }, { "name": "Black Elegance Jeans", "price": 69.99, "quantity": 2, }, { "name": "Slim Fit Jeans", "price": 55.99, "quantity": 1, }, ],}<ArrayInput> expects a single child, which must be a form iterator component. A form iterator is a component rendering a field array (the object returned by react-hook-form’s useFieldArray). For instance, the <SimpleFormIterator> component displays an array of Inputs in an unordered list (<ul>), one sub-form by list item (<li>). It also provides controls for adding and removing a sub-record.
import { Edit, SimpleForm, TextInput, ArrayInput, NumberInput, SimpleFormIterator} from '@/components/admin';
const OrderEdit = () => ( <Edit> <SimpleForm> <TextInput source="customer" /> <TextInput source="date" type="date" /> <ArrayInput source="items"> <SimpleFormIterator inline> <TextInput source="name" /> <NumberInput source="price" /> <NumberInput source="quantity" /> </SimpleFormIterator> </ArrayInput> </SimpleForm> </Edit>);<SimpleFormIterator> will transform the source of its child Input components into nested inputs (items.0.name). Check the <SimpleFormIterator> documentation below for details about how to customize the sub form layout.
| Prop | Required | Type | Default | Description |
|---|---|---|---|---|
source | Required | string | - | Array field name |
children | Required | ReactNode | - | Iterator component(s) |
className | Optional | string | - | Classes |
defaultValue | Optional | any[] | [] | Initial array |
helperText | Optional | ReactNode | - | Help text |
isPending | Optional | boolean | - | Show skeleton |
label | Optional | string | Inferred | Label text |
validate | Optional | Validator | Validator[] | - | Array-level validation |
<SimpleFormIterator>
Section titled “<SimpleFormIterator>”Iterator for repeating groups inside <ArrayInput>. Renders each item with reorder, remove, and add controls.
| Prop | Required | Type | Default | Description |
|---|---|---|---|---|
addButton | Optional | ReactElement | Default | Custom add button |
className | Optional | string | - | Wrapper classes |
disableAdd | Optional | boolean | false | Hide add button |
disableClear | Optional | boolean | false | Hide clear-all button |
disableRemove | Optional | boolean | (record)=>boolean | false | Disable remove globally or per record |
disableReordering | Optional | boolean | false | Hide move up/down |
getItemLabel | Optional | boolean | (index)=>string|ReactElement | false | Add per-item label |
inline | Optional | boolean | false | Arrange child inputs horizontally (responsive) |
removeButton | Optional | ReactElement | Default | Custom remove button |
reOrderButtons | Optional | ReactElement | Default | Custom reorder buttons |
Global validation
Section titled “Global validation”If you are using an <ArrayInput> inside a form with global validation, you need to shape the errors object returned by the validate function like an array too.
{ authors: [ {}, { name: 'A name is required', role: 'ra.validation.required' // translation keys are supported too }, ],}Disabling The Input
Section titled “Disabling The Input”<ArrayInput> does not support the disabled and readOnly props.
If you need to disable the input, set the <SimpleFormIterator disabled> prop, and make the child inputs readOnly:
const OrderEdit = () => ( <Edit> <SimpleForm> <TextInput source="customer" /> <DateInput source="date" /> <ArrayInput source="items"> <SimpleFormIterator inline disabled> <TextInput source="name" readOnly/> <NumberInput source="price" readOnly /> <NumberInput source="quantity" readOnly /> </SimpleFormIterator> </ArrayInput> </SimpleForm> </Edit>);Changing An Item’s Value Programmatically
Section titled “Changing An Item’s Value Programmatically”You can leverage react-hook-form’s setValue method to change an item’s value programmatically.
However you need to know the name under which the input was registered in the form, and this name is dynamically generated depending on the index of the item in the array.
To get the name of the input for a given index, you can leverage the SourceContext created by ra-core, which can be accessed using the useSourceContext hook.
This context provides a getSource function that returns the effective source for an input in the current context, which you can use as input name for setValue.
Here is an example where we leverage getSource and setValue to change the role of an user to ‘admin’ when the ‘Make Admin’ button is clicked:
import { ArrayInput, SimpleFormIterator, TextInput } from '@/components/admin';import { Button } from '@/components/ui/button';import { useSourceContext } from 'ra-core';import { useFormContext } from 'react-hook-form';
const ChangeRoleButton = () => { const sourceContext = useSourceContext(); const { setValue } = useFormContext();
const onClick = () => { // sourceContext.getSource('role') will for instance return // 'users.0.role' setValue(sourceContext.getSource('role'), 'admin'); };
return ( <Button onClick={onClick} size="small" sx={{ minWidth: 120 }}> Make admin </Button> );};
const UserArray = () => ( <ArrayInput source="users"> <SimpleFormIterator inline> <TextInput source="name" helperText={false} /> <TextInput source="role" helperText={false} /> <ChangeRoleButton /> </SimpleFormIterator> </ArrayInput>);