Hi guys. In this article we will create a advance multiple tags input using React.JS and a bit of CSS.
Where user can
- Add tag by entering comma(,) .
- Add tag by pressing "Enter" key.
- Edit last tag by entering "Back Space".
- On Blur add input text to Tag list.
No time to ready then here is the CodeSandbox
link.
CodeSandbox
DEMO
CodeSandbox
Code Example
Step-1
Create A react js project.
npx create-react-app my_app
Step-2
Then lets create a component name of AdavnceTagsInput.js.
and the code with logic whick will look like below
import React, { useState, useRef } from "react";
import "./AdavnceTagsInput.css";
export const AdavnceTagsInput = () => {
// to store input field data
const [tagText, setTagText] = useState("");
// to store tags data in array form
const [tags, setTags] = useState([]);
// to handle focus or blur state of input field
const [isKeyReleased, setIsKeyReleased] = React.useState(false);
const inputRef = useRef(null);
const onChange = (e) => {
const { value } = e.target;
setTagText(value);
};
return (
<div className="CustomTagComp" >
<div className="selected_tag">
{tags.map((tag, index) => (
<div key={index} style={{ display: "flex" }}>
<span className="selected_tag_text">{tag}</span>
<button className="selected_tag_button" >
✕
</button>
</div>
))}
<input
value={tagText}
placeholder="Enter Tag"
className="tags_input"
/>
</div>
</div>
);
};
Step-3
Then lets add onKeyDown function, where we will check whether input field value is there . And on Enter or using comma(,) we will add value to tag list
// handle key down
const onKeyDown = (e) => {
const { key } = e;
const trimmedInput = tagText.trim(); // remove extra space from both side
// on entering "," add text to tag list
if (key === "," && trimmedInput.length && !tags.includes(trimmedInput)) {
e.preventDefault();
setTags(
(prevState) =>
!prevState.includes(trimmedInput) && [...prevState, trimmedInput]
);
setTagText("");
}
// on press enter add text to tag list
if (
key === "Enter" &&
trimmedInput.length &&
!tags.includes(trimmedInput)
) {
e.preventDefault();
setTags(
(prevState) =>
!prevState.includes(trimmedInput) && [...prevState, trimmedInput]
);
setTagText("");
}
// on press back space user can exit last tag list
if (
key === "Backspace" &&
!tagText.length &&
tags.length &&
isKeyReleased
) {
const tagsCopy = [...tags];
const poppedTag = tagsCopy.pop();
e.preventDefault();
setTags(tagsCopy);
setTagText(poppedTag);
}
setIsKeyReleased(false);
};
Step-4
Then lets add onKeyUp function, where we will make our isKeyReleased false ,means we move out of input field
const onKeyUp = () => {
setIsKeyReleased(true);
};
Step-5
Then lets add removeTag function, when user click on remove button in tag, we will remove tag from tag list .
const removeTag = (index) => {
setTags((prevState) => prevState.filter((tag, i) => i !== index));
};
Step-6
Then lets add handleFocus function, So when user click on anywhere of input tag box, we will make input field focus .
const handleFocus = (e) => {
let input = inputRef.current;
e.stopPropagation();
if (tags && tags.length > 0) {
input.classList.remove("d-none");
}
input.focus();
};
Step-7
Then lets add handleBlur function, When user enter some text and move out of input field without adding value to tag list, then we will add the value to tag list automatically.
const handleBlur = () => {
setIsKeyReleased(false);
if (tagText) {
let trimmedInput = tagText.replace(/,/g, "");
if (trimmedInput.length && !tags.includes(trimmedInput)) {
setTags(
(prevState) =>
!prevState.includes(trimmedInput) && [...prevState, trimmedInput]
);
}
setTagText("");
}
};
Finally
So finally our AdavnceTagsInput.js
will look like this.
import React, { useState, useRef } from "react";
import "./AdavnceTagsInput.css";
export const AdavnceTagsInput = () => {
// to store input field data
const [tagText, setTagText] = useState("");
// to store tags data in array form
const [tags, setTags] = useState([]);
// to handle focus or blur state of input field
const [isKeyReleased, setIsKeyReleased] = React.useState(false);
const inputRef = useRef(null);
const onChange = (e) => {
const { value } = e.target;
setTagText(value);
};
// handle key down
const onKeyDown = (e) => {
const { key } = e;
const trimmedInput = tagText.trim(); // remove extra space from both side
// on entering "," add text to tag list
if (key === "," && trimmedInput.length && !tags.includes(trimmedInput)) {
e.preventDefault();
setTags(
(prevState) =>
!prevState.includes(trimmedInput) && [...prevState, trimmedInput]
);
setTagText("");
}
// on press enter add text to tag list
if (
key === "Enter" &&
trimmedInput.length &&
!tags.includes(trimmedInput)
) {
e.preventDefault();
setTags(
(prevState) =>
!prevState.includes(trimmedInput) && [...prevState, trimmedInput]
);
setTagText("");
}
// on press back space user can exit last tag list
if (
key === "Backspace" &&
!tagText.length &&
tags.length &&
isKeyReleased
) {
const tagsCopy = [...tags];
const poppedTag = tagsCopy.pop();
e.preventDefault();
setTags(tagsCopy);
setTagText(poppedTag);
}
setIsKeyReleased(false);
};
// handle key up
const onKeyUp = () => {
setIsKeyReleased(true);
};
// handle remove tag from tag list
const removeTag = (index) => {
setTags((prevState) => prevState.filter((tag, i) => i !== index));
};
// handle focus
const handleFocus = (e) => {
let input = inputRef.current;
e.stopPropagation();
if (tags && tags.length > 0) {
input.classList.remove("d-none");
}
input.focus();
};
// handle blur
const handleBlur = () => {
setIsKeyReleased(false);
if (tagText) {
let trimmedInput = tagText.replace(/,/g, "");
if (trimmedInput.length && !tags.includes(trimmedInput)) {
setTags(
(prevState) =>
!prevState.includes(trimmedInput) && [...prevState, trimmedInput]
);
}
setTagText("");
}
};
return (
<div className="CustomTagComp" onClick={handleFocus}>
<div className="selected_tag">
{tags.map((tag, index) => (
<div key={index} style={{ display: "flex" }}>
<span className="selected_tag_text">{tag}</span>
<button
onClick={() => removeTag(index)}
className="selected_tag_button"
>
✕
</button>
</div>
))}
<input
ref={inputRef}
value={tagText}
placeholder="Enter Tag"
onKeyDown={onKeyDown}
onBlur={handleBlur}
onKeyUp={onKeyUp}
onChange={onChange}
className="tags_input"
/>
</div>
</div>
);
};
And at end Add CSS
So finally our AdavnceTagsInput.css
will look like this.
.selected_tag {
display: flex;
align-items: center;
flex-wrap: wrap;
cursor: text;
border: 2px solid;
padding: 4px;
border-radius: 4px;
gap: 4px;
}
.selected_tag_text {
/* font-size: 11px; */
color: rgb(0, 0, 0);
padding: 4px;
background-color: rgb(218, 216, 216);
border-radius: 4px 0px 0px 4px;
border: none;
word-break: break-all;
cursor: text;
}
.selected_tag_button {
/* font-size: 9px; */
border: none;
background-color: rgb(218, 216, 216);
padding: 4px;
border-left: 1px solid #ffffff;
border-radius: 0px 4px 4px 0px;
color: rgb(0, 0, 0);
margin-right: 5px;
font-weight: bold;
cursor: pointer;
}
.tags_input {
box-sizing: border-box;
width: 0;
min-width: 30px;
flex-grow: 1;
border: 0;
margin: 0;
outline: 0;
}
.tag_input:focus-visible {
outline: none;
}
And that's all we have successfully create a tags input using React and Bit of JavaScript.
Found it helpful? Hit like and share with other
Make sure you checkout my other articles
Top comments (0)