useInput
This hook lets you build custom inputs for react-admin. It’s a wrapper around react-hook-form’s useController
.
React-admin adds functionality to react-hook-form:
- handling of custom event emitters like
onChange
, - support for an array of validators,
- detection of required fields to add an asterisk to the field label,
- parse and format to translate record values to form values and vice-versa.
Usage
useInput
expects at least a source
, and returns an object with the following properties:
{ id, field, fieldState, formState, isRequired }
For instance, to build a custom input for a title
field:
import { useInput } from 'react-admin';
const TitleInput = ({ source, label }) => {
const { id, field, fieldState } = useInput({ source });
return (
<label htmlFor={id}>
{label}
<input id={id} {...field} />
{fieldState.error && <span>{fieldState.error.message}</span>}
</label>
);
};
Props
Prop | Required | Type | Default | Description |
---|---|---|---|---|
source |
Required | string |
- | The name of the field in the record |
defaultValue |
Optional | any |
- | The default value of the input |
format |
Optional | Function |
- | A function to format the value from the record to the input value |
parse |
Optional | Function |
- | A function to parse the value from the input to the record value |
validate |
Optional | Function | Function[] |
- | A function or an array of functions to validate the input value |
id |
Optional | string |
- | The id of the input |
onChange |
Optional | Function |
- | A function to call when the input value changes |
onBlur |
Optional | Function |
- | A function to call when the input is blurred |
Additional props are passed to react-hook-form’s useController
hook.
Usage with MUI <TextField>
// in LatLongInput.js
import TextField from '@mui/material/TextField';
import { useInput, required } from 'react-admin';
const BoundedTextField = (props) => {
const { onChange, onBlur, ...rest } = props;
const {
field,
fieldState: { isTouched, invalid, error },
formState: { isSubmitted },
isRequired
} = useInput({
// Pass the event handlers to the hook but not the component as the field property already has them.
// useInput will call the provided onChange and onBlur in addition to the default needed by react-hook-form.
onChange,
onBlur,
...props,
});
return (
<TextField
{...field}
label={props.label}
error={(isTouched || isSubmitted) && invalid}
helperText={(isTouched || isSubmitted) && invalid ? error : ''}
required={isRequired}
{...rest}
/>
);
};
const LatLngInput = props => {
const { source, ...rest } = props;
return (
<span>
<BoundedTextField source="lat" label="Latitude" validate={required()} {...rest} />
<BoundedTextField source="lng" label="Longitude" validate={required()} {...rest} />
</span>
);
};
Usage with MUI <Select>
// in SexInput.js
import Select from '@mui/material/Select';
import MenuItem from '@mui/material/MenuItem';
import { useInput } from 'react-admin';
const SexInput = props => {
const {
field,
fieldState: { isTouched, invalid, error },
formState: { isSubmitted }
} = useInput(props);
return (
<Select
label="Sex"
{...field}
>
<MenuItem value="M">Male</MenuItem>
<MenuItem value="F">Female</MenuItem>
</Select>
);
};
export default SexInput;
Tip: useInput
accepts all arguments that you can pass to useController
. Besides, components using useInput
accept props like format
and parse
, to convert values from the form to the input, and vice-versa:
const parse = value => {/* ... */};
const format = value => {/* ... */};
const PersonEdit = () => (
<Edit>
<SimpleForm>
<SexInput
source="sex"
format={formValue => formValue === 0 ? 'M' : 'F'}
parse={inputValue => inputValue === 'M' ? 0 : 1}
/>
</SimpleForm>
</Edit>
);