Here's a sandbox: https://codesandbox.io/s/wild-sea-h2i0m
Here's the code for the Autocomplete from that sandbox:
import React from "react";
import Autocomplete from "@material-ui/lab/Autocomplete";
import Chip from "@material-ui/core/Chip";
import CloseIcon from "@material-ui/icons/Close";
import TextField from "@material-ui/core/TextField";
import { FieldProps } from "formik";
const isEmailValid = (email: string) =>
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
const EmailsField = ({
field,
form: { errors, touched, setTouched, setFieldValue },
...props
}: FieldProps) => {
const name = field.name;
const [value, setValue] = React.useState<string[]>([]);
const [inputValue, setInputValue] = React.useState("");
const handleChange = (event: React.ChangeEvent<{}>, emails: string[]) => {
setTouched({ ...touched, [name]: true });
setValue(emails);
event.persist();
setFieldValue(name, emails);
};
const handleInputChange = (
event: React.ChangeEvent<{}>,
newInputValue: string
) => {
const options = newInputValue.split(/[ ,]+/);
const fieldValue = value
.concat(options)
.map(x => x.trim())
.filter(x => x);
if (options.length > 1) {
handleChange(event, fieldValue);
} else {
setInputValue(newInputValue);
}
};
return (
<Autocomplete<string>
multiple
disableClearable={true}
options={[]}
freeSolo
renderTags={(emails, getTagProps) =>
emails.map((email, index) => (
<Chip
deleteIcon={<CloseIcon />}
variant="default"
label={email}
color={isEmailValid(email) ? "primary" : "secondary"}
{...getTagProps({ index })}
/>
))
}
value={value}
inputValue={inputValue}
onChange={handleChange}
onInputChange={handleInputChange}
renderInput={params => (
<TextField
{...params}
name={name}
error={touched[name] && Boolean(errors.emails)}
helperText={touched[name] && errors.emails}
variant="outlined"
InputProps={{ ...params.InputProps }}
{...props}
/>
)}
/>
);
};
export default EmailsField;
I'm unable to make the value typed by the user become a single option after the user types and then presses the tab keyboard button to move to the submit button.
Any idea how?
You can accomplish this by adding a handler for onKeyDown
:
const handleKeyDown = (event: React.KeyboardEvent) => {
switch (event.key) {
case "Tab": {
if (inputValue.length > 0) {
handleChange(event, value.concat([inputValue]));
}
break;
}
default:
}
};
and then adding that to the text input via inputProps
:
renderInput={params => {
params.inputProps.onKeyDown = handleKeyDown;
return (
<TextField
{...params}
name={name}
error={touched[name] && Boolean(errors.emails)}
helperText={touched[name] && errors.emails}
variant="outlined"
{...props}
/>
);
}}
Here's the full new code for the EmailsField
component from your sandbox:
import React from "react";
import Autocomplete from "@material-ui/lab/Autocomplete";
import Chip from "@material-ui/core/Chip";
import CloseIcon from "@material-ui/icons/Close";
import TextField from "@material-ui/core/TextField";
import { FieldProps } from "formik";
const isEmailValid = (email: string) =>
/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
const EmailsField = ({
field,
form: { errors, touched, setTouched, setFieldValue },
...props
}: FieldProps) => {
const name = field.name;
const [value, setValue] = React.useState<string[]>([]);
const [inputValue, setInputValue] = React.useState("");
const handleChange = (event: React.ChangeEvent<{}>, emails: string[]) => {
setTouched({ ...touched, [name]: true });
setValue(emails);
event.persist();
setFieldValue(name, emails);
};
const handleInputChange = (
event: React.ChangeEvent<{}>,
newInputValue: string
) => {
const options = newInputValue.split(/[ ,]+/);
const fieldValue = value
.concat(options)
.map(x => x.trim())
.filter(x => x);
if (options.length > 1) {
handleChange(event, fieldValue);
} else {
setInputValue(newInputValue);
}
};
const handleKeyDown = (event: React.KeyboardEvent) => {
switch (event.key) {
case "Tab": {
if (inputValue.length > 0) {
handleChange(event, value.concat([inputValue]));
}
break;
}
default:
}
};
return (
<Autocomplete<string>
multiple
disableClearable={true}
options={[]}
freeSolo
renderTags={(emails, getTagProps) =>
emails.map((email, index) => (
<Chip
deleteIcon={<CloseIcon />}
variant="default"
label={email}
color={isEmailValid(email) ? "primary" : "secondary"}
{...getTagProps({ index })}
/>
))
}
value={value}
inputValue={inputValue}
onChange={handleChange}
onInputChange={handleInputChange}
renderInput={params => {
params.inputProps.onKeyDown = handleKeyDown;
return (
<TextField
{...params}
name={name}
error={touched[name] && Boolean(errors.emails)}
helperText={touched[name] && errors.emails}
variant="outlined"
{...props}
/>
);
}}
/>
);
};
export default EmailsField;
Related answer: Material ui Autocomplete: can tags be created on events aside from 'Enter' events?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With