So i was using this TagsInput as shared in the link for codesandbox
=&file=/src/TagsInput.js
The issue im facing is if there are alot of chips then the chips go out of the text field
What im trying to do is to find a way where i can have like a multiline Textfield so that if chips are too many they go to next line like they do in Autoplete.
export default function TagsInput({ ...props }) {
const classes = useStyles();
const { selectedTags, placeholder, tags, ...other } = props;
const [inputValue, setInputValue] = React.useState("");
const [selectedItem, setSelectedItem] = React.useState([]);
useEffect(() => {
setSelectedItem(tags);
}, [tags]);
useEffect(() => {
selectedTags(selectedItem);
}, [selectedItem, selectedTags]);
function handleKeyDown(event) {
if (event.key === "Enter") {
const newSelectedItem = [...selectedItem];
const duplicatedValues = newSelectedItem.indexOf(
event.target.value.trim()
);
if (duplicatedValues !== -1) {
setInputValue("");
return;
}
if (!event.target.value.replace(/\s/g, "").length) return;
newSelectedItem.push(event.target.value.trim());
setSelectedItem(newSelectedItem);
setInputValue("");
}
if (
selectedItem.length &&
!inputValue.length &&
event.key === "Backspace"
) {
setSelectedItem(selectedItem.slice(0, selectedItem.length - 1));
}
}
function handleChange(item) {
let newSelectedItem = [...selectedItem];
if (newSelectedItem.indexOf(item) === -1) {
newSelectedItem = [...newSelectedItem, item];
}
setInputValue("");
setSelectedItem(newSelectedItem);
}
const handleDelete = item => () => {
const newSelectedItem = [...selectedItem];
newSelectedItem.splice(newSelectedItem.indexOf(item), 1);
setSelectedItem(newSelectedItem);
};
function handleInputChange(event) {
setInputValue(event.target.value);
}
return (
<React.Fragment>
<Downshift
id="downshift-multiple"
inputValue={inputValue}
onChange={handleChange}
selectedItem={selectedItem}
>
{({ getInputProps }) => {
const { onBlur, onChange, onFocus, ...inputProps } = getInputProps({
onKeyDown: handleKeyDown,
placeholder
});
return (
<div>
<TextField
InputProps={{
startAdornment: selectedItem.map(item => (
<Chip
key={item}
tabIndex={-1}
label={item}
className={classes.chip}
onDelete={handleDelete(item)}
/>
)),
onBlur,
onChange: event => {
handleInputChange(event);
onChange(event);
},
onFocus
}}
{...other}
{...inputProps}
/>
</div>
);
}}
</Downshift>
</React.Fragment>
);
}
TagsInput.defaultProps = {
tags: []
};
TagsInput.propTypes = {
selectedTags: PropTypes.func.isRequired,
tags: PropTypes.arrayOf(PropTypes.string)
};
So i was using this TagsInput as shared in the link for codesandbox
https://codesandbox.io/s/material-ui-input-with-chips-0s2j4?from-embed=&file=/src/TagsInput.js
The issue im facing is if there are alot of chips then the chips go out of the text field
What im trying to do is to find a way where i can have like a multiline Textfield so that if chips are too many they go to next line like they do in Autoplete.
export default function TagsInput({ ...props }) {
const classes = useStyles();
const { selectedTags, placeholder, tags, ...other } = props;
const [inputValue, setInputValue] = React.useState("");
const [selectedItem, setSelectedItem] = React.useState([]);
useEffect(() => {
setSelectedItem(tags);
}, [tags]);
useEffect(() => {
selectedTags(selectedItem);
}, [selectedItem, selectedTags]);
function handleKeyDown(event) {
if (event.key === "Enter") {
const newSelectedItem = [...selectedItem];
const duplicatedValues = newSelectedItem.indexOf(
event.target.value.trim()
);
if (duplicatedValues !== -1) {
setInputValue("");
return;
}
if (!event.target.value.replace(/\s/g, "").length) return;
newSelectedItem.push(event.target.value.trim());
setSelectedItem(newSelectedItem);
setInputValue("");
}
if (
selectedItem.length &&
!inputValue.length &&
event.key === "Backspace"
) {
setSelectedItem(selectedItem.slice(0, selectedItem.length - 1));
}
}
function handleChange(item) {
let newSelectedItem = [...selectedItem];
if (newSelectedItem.indexOf(item) === -1) {
newSelectedItem = [...newSelectedItem, item];
}
setInputValue("");
setSelectedItem(newSelectedItem);
}
const handleDelete = item => () => {
const newSelectedItem = [...selectedItem];
newSelectedItem.splice(newSelectedItem.indexOf(item), 1);
setSelectedItem(newSelectedItem);
};
function handleInputChange(event) {
setInputValue(event.target.value);
}
return (
<React.Fragment>
<Downshift
id="downshift-multiple"
inputValue={inputValue}
onChange={handleChange}
selectedItem={selectedItem}
>
{({ getInputProps }) => {
const { onBlur, onChange, onFocus, ...inputProps } = getInputProps({
onKeyDown: handleKeyDown,
placeholder
});
return (
<div>
<TextField
InputProps={{
startAdornment: selectedItem.map(item => (
<Chip
key={item}
tabIndex={-1}
label={item}
className={classes.chip}
onDelete={handleDelete(item)}
/>
)),
onBlur,
onChange: event => {
handleInputChange(event);
onChange(event);
},
onFocus
}}
{...other}
{...inputProps}
/>
</div>
);
}}
</Downshift>
</React.Fragment>
);
}
TagsInput.defaultProps = {
tags: []
};
TagsInput.propTypes = {
selectedTags: PropTypes.func.isRequired,
tags: PropTypes.arrayOf(PropTypes.string)
};
Share
Improve this question
asked Feb 28, 2023 at 23:00
Ahsan BalochAhsan Baloch
2422 silver badges12 bronze badges
1 Answer
Reset to default 15You can use AutoComplete
to achieve this.
CodeSandbox Example
<Autoplete
clearIcon={false}
options={[]}
freeSolo
multiple
renderTags={(value, props) =>
value.map((option, index) => (
<Chip label={option} {...props({ index })} />
))
}
renderInput={(params) => <TextField label="Add Tags" {...params} />}
/>