diff --git a/docs/ArrayInput.md b/docs/ArrayInput.md
index 03ddb9da29..28a3da2c62 100644
--- a/docs/ArrayInput.md
+++ b/docs/ArrayInput.md
@@ -133,3 +133,54 @@ const OrderEdit = () => (
);
```
+
+## Changing An Item's Value Programmatically
+
+You can leverage `react-hook-form`'s [`setValue`](https://react-hook-form.com/docs/useform/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 react-admin, 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:
+
+{% raw %}
+
+```tsx
+import { ArrayInput, SimpleFormIterator, TextInput, useSourceContext } from 'react-admin';
+import { useFormContext } from 'react-hook-form';
+import { Button } from '@mui/material';
+
+const MakeAdminButton = () => {
+ const sourceContext = useSourceContext();
+ const { setValue } = useFormContext();
+
+ const onClick = () => {
+ // sourceContext.getSource('role') will for instance return
+ // 'users.0.role'
+ setValue(sourceContext.getSource('role'), 'admin');
+ };
+
+ return (
+
+ );
+};
+
+const UserArray = () => (
+
+
+
+
+
+
+
+);
+```
+
+{% endraw %}
+
+**Tip:** If you only need the item's index, you can leverage the [`useSimpleFormIteratorItem` hook](./SimpleFormIterator.md#getting-the-element-index) instead.
\ No newline at end of file
diff --git a/docs/Inputs.md b/docs/Inputs.md
index 30186752cd..7f1a34f72c 100644
--- a/docs/Inputs.md
+++ b/docs/Inputs.md
@@ -647,7 +647,7 @@ const OrderEdit = () => (
);
```
-**Tip**: When used inside an `ArrayInput`, `` provides one additional property to its child function called `scopedFormData`. It's an object containing the current values of the *currently rendered item*. This allows you to create dependencies between inputs inside a ``, as in the following example:
+**Tip**: When used inside an ``, `` provides one additional property to its child function called `scopedFormData`. It's an object containing the current values of the *currently rendered item*. This allows you to create dependencies between inputs inside a ``, as in the following example:
```tsx
import { FormDataConsumer } from 'react-admin';
@@ -682,6 +682,8 @@ const PostEdit = () => (
**Tip:** TypeScript users will notice that `scopedFormData` is typed as an optional parameter. This is because the `` component can be used outside of an `` and in that case, this parameter will be `undefined`. If you are inside an ``, you can safely assume that this parameter will be defined.
+**Tip:** If you need to access the *effective* source of an input inside an ``, for example to change the value programmatically using `setValue`, you will need to leverage the [`useSourceContext` hook](./ArrayInput#changing-an-items-value-programmatically).
+
## Hiding Inputs Based On Other Inputs
You may want to display or hide inputs based on the value of another input - for instance, show an `email` input only if the `hasEmail` boolean input has been ticked to `true`.
diff --git a/docs/ReferenceManyInput.md b/docs/ReferenceManyInput.md
index 615e5f1569..68c1224255 100644
--- a/docs/ReferenceManyInput.md
+++ b/docs/ReferenceManyInput.md
@@ -300,3 +300,63 @@ const ProductEdit = () => (
- `` cannot be used with `undoable` mutations in a `` view.
- `` cannot have a `` or a `` as one of its children.
- `` does not support server side validation.
+
+## Changing An Item's Value Programmatically
+
+You can leverage `react-hook-form`'s [`setValue`](https://react-hook-form.com/docs/useform/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 react-admin, 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 prefill the email input when the 'Prefill email' button is clicked:
+
+{% raw %}
+
+```tsx
+import { SimpleFormIterator, TextInput, useSourceContext } from 'react-admin';
+import { ReferenceManyInput } from '@react-admin/ra-relationships';
+import { useFormContext } from 'react-hook-form';
+import { Button } from '@mui/material';
+
+const PrefillEmail = () => {
+ const sourceContext = useSourceContext();
+ const { setValue, getValues } = useFormContext();
+
+ const onClick = () => {
+ const firstName = getValues(sourceContext.getSource('first_name'));
+ const lastName = getValues(sourceContext.getSource('last_name'));
+ const email = `${
+ firstName ? firstName.toLowerCase() : ''
+ }.${lastName ? lastName.toLowerCase() : ''}@school.com`;
+ setValue(sourceContext.getSource('email'), email);
+ };
+
+ return (
+
+ );
+};
+
+const StudentsInput = () => (
+
+
+
+
+
+
+
+
+);
+```
+
+{% endraw %}
+
+**Tip:** If you only need the item's index, you can leverage the [`useSimpleFormIteratorItem` hook](./SimpleFormIterator.md#getting-the-element-index) instead.
diff --git a/docs/ReferenceOneInput.md b/docs/ReferenceOneInput.md
index 3b152a0458..b7db80a8fc 100644
--- a/docs/ReferenceOneInput.md
+++ b/docs/ReferenceOneInput.md
@@ -234,58 +234,70 @@ Name of the field carrying the relationship on the referenced resource. For inst
```
-## Customizing The Child Inputs
+## Limitations
+
+- `` cannot be used inside an `` or a ``.
+- `` cannot have a `` or a `` as one of its children.
+- `` does not support server side validation.
+
+## Changing An Item's Value Programmatically
+
+You can leverage `react-hook-form`'s [`setValue`](https://react-hook-form.com/docs/useform/setvalue) method to change the reference record's value programmatically.
-`` works by cloning its children and overriding their `source` prop, to add a temporary field name prefix. This means that, if you need to nest your inputs inside another component, you will need to propagate the `source` prop to them.
+However you need to know the `name` under which the inputs were registered in the form, and these names are dynamically generated by ``.
-In this example, the `` component is wrapped inside a `` component. That adds an icon and additional styling.
+To get the name of a specific input, you can leverage the `SourceContext` created by react-admin, 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 update some of the book details when the 'Update book details' button is clicked:
{% raw %}
+
```tsx
-import AccountCircle from '@mui/icons-material/AccountCircle';
-import AutoStoriesIcon from '@mui/icons-material/AutoStories';
-import CalendarMonthIcon from '@mui/icons-material/CalendarMonth';
-import ClassIcon from '@mui/icons-material/Class';
-import LanguageIcon from '@mui/icons-material/Language';
-import { Box, SxProps } from '@mui/material';
-import * as React from 'react';
-import { TextInput } from 'react-admin';
+import { NumberInput, TextInput, useSourceContext } from 'react-admin';
import { ReferenceOneInput } from '@react-admin/ra-relationships';
-
-const MyCustomInput = ({
- source,
- icon: Icon,
-}: {
- source: string;
- icon: React.FunctionComponent<{ sx?: SxProps }>;
-}) => (
-
-
-
-
-);
-
-export const CustomInputs = () => (
-
-
-
-
-
-
+import { useFormContext } from 'react-hook-form';
+import { Button, Stack, Box } from '@mui/material';
+
+const UpdateBookDetails = () => {
+ const sourceContext = useSourceContext();
+ const { setValue } = useFormContext();
+
+ const onClick = () => {
+ // Generate random values for year and pages
+ const year = 1000 + Math.floor(Math.random() * 1000);
+ const pages = 100 + Math.floor(Math.random() * 900);
+ setValue(sourceContext.getSource('year'), year);
+ setValue(sourceContext.getSource('pages'), pages);
+ };
+
+ return (
+
+ );
+};
+
+const BookDetails = () => (
+
+
+
+
+
+
+
+
+
+
+
);
```
-{% endraw %}
-
-
-## Limitations
-
-- `` cannot be used inside an `` or a ``.
-- `` cannot have a `` or a `` as one of its children.
-- `` does not support server side validation.
+{% endraw %}
diff --git a/docs/SimpleFormIterator.md b/docs/SimpleFormIterator.md
index 64e4c615a5..7fc9425476 100644
--- a/docs/SimpleFormIterator.md
+++ b/docs/SimpleFormIterator.md
@@ -430,3 +430,44 @@ This property accepts the following subclasses:
| `RaSimpleFormIterator-inline` | Applied to rows when `inline` is true |
| `RaSimpleFormIterator-line` | Applied to each row |
| `RaSimpleFormIterator-list` | Applied to the `
` element |
+
+## Getting The Element Index
+
+Inside a ``, you can access the index of the current element using the `useSimpleFormIteratorItem` hook.
+
+{% raw %}
+
+```tsx
+import {
+ TextInput,
+ ArrayInput,
+ SimpleFormIterator,
+ useSimpleFormIteratorItem,
+} from 'react-admin';
+import { Typography } from '@mui/material';
+
+const IndexField = () => {
+ const { index } = useSimpleFormIteratorItem();
+ return (
+
+ #{index + 1}:
+
+ );
+};
+
+const UserArray = () => (
+
+
+
+
+
+
+
+);
+```
+
+{% endraw %}
+
+**Tip:** This hook also returns the total number of elements (`total`).
+
+**Tip:** If you need the index to change the value of an input programmatically, you should use the [`useSourceContext` hook](./ArrayInput.md#changing-an-items-value-programmatically) instead.
diff --git a/docs/TranslatableInputs.md b/docs/TranslatableInputs.md
index c604b74be2..df8ac3aa6f 100644
--- a/docs/TranslatableInputs.md
+++ b/docs/TranslatableInputs.md
@@ -198,3 +198,53 @@ You can add validators to any of the inputs inside a `TranslatableInputs`. If an
```
+
+## Changing The Value Programmatically
+
+You can leverage `react-hook-form`'s [`setValue`](https://react-hook-form.com/docs/useform/setvalue) method to change an input'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 locale.
+
+To get the name of the input for a given locale, you can leverage the `SourceContext` created by react-admin, 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 pre-fill the 'description' input using the value of the 'title' input when the corresponding button is clicked:
+
+{% raw %}
+
+```tsx
+import { TranslatableInputs, TextInput, useSourceContext } from 'react-admin';
+import { useFormContext } from 'react-hook-form';
+import { Button } from '@mui/material';
+
+const PrefillWithTitleButton = () => {
+ const sourceContext = useSourceContext();
+ const { setValue, getValues } = useFormContext();
+
+ const onClick = () => {
+ setValue(
+ // sourceContext.getSource('description') will for instance return
+ // 'description.en'
+ sourceContext.getSource('description'),
+ getValues(sourceContext.getSource('title'))
+ );
+ };
+
+ return (
+
+ );
+};
+
+const MyInputs = () => (
+
+
+
+
+
+);
+```
+
+{% endraw %}
diff --git a/docs/Upgrade.md b/docs/Upgrade.md
index 4fa42ee457..377e8399af 100644
--- a/docs/Upgrade.md
+++ b/docs/Upgrade.md
@@ -975,6 +975,47 @@ const PostEdit = () => (
);
```
+If you still need to access the *effective* source of an input inside an ``, for example to change the value programmatically using `setValue`, you will need to leverage the [`useSourceContext` hook](./ArrayInput#changing-an-items-value-programmatically).
+
+{% raw %}
+
+```tsx
+import { ArrayInput, SimpleFormIterator, TextInput, useSourceContext } from 'react-admin';
+import { useFormContext } from 'react-hook-form';
+import { Button } from '@mui/material';
+
+const MakeAdminButton = () => {
+ const sourceContext = useSourceContext();
+ const { setValue } = useFormContext();
+
+ const onClick = () => {
+ // sourceContext.getSource('role') will for instance return
+ // 'users.0.role'
+ setValue(sourceContext.getSource('role'), 'admin');
+ };
+
+ return (
+
+ );
+};
+
+const UserArray = () => (
+
+
+
+
+
+
+
+);
+```
+
+{% endraw %}
+
+**Tip:** If you only need the item's index, you can leverage the [`useSimpleFormIteratorItem` hook](./SimpleFormIterator.md#getting-the-element-index) instead.
+
### Mutation Middlewares No Longer Receive The Mutation Options
Mutations middlewares no longer receive the mutation options:
diff --git a/packages/ra-ui-materialui/src/input/ArrayInput/ArrayInput.stories.tsx b/packages/ra-ui-materialui/src/input/ArrayInput/ArrayInput.stories.tsx
index 27f8d29b1e..d775191e67 100644
--- a/packages/ra-ui-materialui/src/input/ArrayInput/ArrayInput.stories.tsx
+++ b/packages/ra-ui-materialui/src/input/ArrayInput/ArrayInput.stories.tsx
@@ -6,8 +6,9 @@ import {
Resource,
testI18nProvider,
TestMemoryRouter,
+ useSourceContext,
} from 'ra-core';
-import { InputAdornment } from '@mui/material';
+import { Button, InputAdornment } from '@mui/material';
import { Edit, Create } from '../../detail';
import { SimpleForm, TabbedForm } from '../../form';
@@ -884,3 +885,42 @@ export const WithReferenceField = () => (
);
+
+const MakeAdminButton = () => {
+ const sourceContext = useSourceContext();
+ const { setValue } = useFormContext();
+
+ const onClick = () => {
+ setValue(sourceContext.getSource('role'), 'admin');
+ };
+
+ return (
+
+ );
+};
+
+const BookEditSetValue = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export const SetValue = () => (
+
+
+
+
+
+);
diff --git a/packages/ra-ui-materialui/src/input/ArrayInput/SimpleFormIterator.stories.tsx b/packages/ra-ui-materialui/src/input/ArrayInput/SimpleFormIterator.stories.tsx
index 2f61d77d02..03505e4d6f 100644
--- a/packages/ra-ui-materialui/src/input/ArrayInput/SimpleFormIterator.stories.tsx
+++ b/packages/ra-ui-materialui/src/input/ArrayInput/SimpleFormIterator.stories.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { Button } from '@mui/material';
+import { Button, Typography } from '@mui/material';
import { Edit } from '../../detail';
import { SimpleForm } from '../../form';
@@ -8,6 +8,7 @@ import { SimpleFormIterator } from './SimpleFormIterator';
import { TextInput } from '../TextInput';
import { AdminContext } from '../../AdminContext';
import { defaultTheme } from '../../theme/defaultTheme';
+import { useSimpleFormIteratorItem } from './useSimpleFormIteratorItem';
export default { title: 'ra-ui-materialui/input/SimpleFormIterator' };
@@ -211,3 +212,22 @@ export const Theming = () => (
);
+
+const IndexField = () => {
+ const { index } = useSimpleFormIteratorItem();
+ return (
+
+ #{index + 1}:
+
+ );
+};
+
+export const UseSimpleFormIteratorItem = () => (
+
+
+
+
+
+
+
+);
diff --git a/packages/ra-ui-materialui/src/input/TranslatableInputs.stories.tsx b/packages/ra-ui-materialui/src/input/TranslatableInputs.stories.tsx
index 8fbc627e17..cf55bb99ed 100644
--- a/packages/ra-ui-materialui/src/input/TranslatableInputs.stories.tsx
+++ b/packages/ra-ui-materialui/src/input/TranslatableInputs.stories.tsx
@@ -8,6 +8,9 @@ import { SimpleForm } from '../form';
import { TranslatableInputs } from './TranslatableInputs';
import { FormInspector } from './common';
import { TextInput } from './TextInput';
+import { useSourceContext } from 'ra-core';
+import { useFormContext } from 'react-hook-form';
+import { Button } from '@mui/material';
export default { title: 'ra-ui-materialui/input/TranslatableInputs' };
@@ -69,7 +72,36 @@ const Wrapper = ({ children }) => (
{children}
+