DEV Community

Praveen Bisht
Praveen Bisht

Posted on • Edited on • Originally published at prvnbist.com

Create a tags input component in ReactJs

Tags Input Demo

Project Setup

We are going to be building the component using ReactJs. Let's start by installing the essentials. First we're going to create a react app using React's CRA or you can use any starter kit to begin with. Let's setup our React app.



npx create-react-app tags-input
cd tags-input


Enter fullscreen mode Exit fullscreen mode

Let's get started!

In the index.js file we're going to write the code for our base component App, you can name it anything you'd like.



// index.js
import React from "react";
import ReactDOM from "react-dom";
import "./styles.scss";

const App = () => {
    return (
        <div className="App">
            <span>Hello World!</span>
        </div>
    );
};

ReactDOM.render(<App />, document.getElementById("root"));


Enter fullscreen mode Exit fullscreen mode

Tags Input Component

We're going to be using functional components and React's useState hook to make it stateful.



// TagsInput.jsx
import React from "react";
const TagsInput = () => {
    const [tags, setTags] = React.useState([]);
    return (
        <div className="tags-input">
            <ul>
                {tags.map((tag, index) => (
                    <li key={index}>
                        <span>{tag}</span>
                        <i className="material-icons">close</i>
                    </li>
                ))}
            </ul>
            <input
                type="text"
                placeholder="Press enter to add tags"
            />
        </div>
    );
};
export default TagsInput;


Enter fullscreen mode Exit fullscreen mode

Since we are going to be storing an array of tags in the state, so we can initialize it as empty array. useState hook return two values i.e the current state( and a function that can used to update the state. We're using array destructuring to get both the values from the useState. The current state in our case is called tags and the function to update it is called setTags.

Then within the return function we're mapping the tags array and displaying all the tags that will be added by the user in the state.

Add tags functionality

Let's create the functionality to add tags. We're going add an event handler onKeyUp to our input tag and return a function called addTags() and pass in the event as an argument.



// TagsInput.jsx
...
<input
    type="text"
    onKeyUp={event => addTags(event)}
    placeholder="Press enter to add tags"
/>
...


Enter fullscreen mode Exit fullscreen mode

Next we'll define the addTags() function above return in our component.



// TagsInput.jsx
import React from "react";
const TagsInput = () => {
    const [tags, setTags] = React.useState([]);
    const addTags = event => {
        if (event.key === "Enter" && event.target.value !== "") {
            setTags([...tags, event.target.value]);
            event.target.value = "";
        }
    };
    return (
    ...
    );
};


Enter fullscreen mode Exit fullscreen mode

We can use keycodes to make sure that the tags are only added to state if the user has pressed Enter key. Alongside that we're also adding one more condition which is to prevent empty tags from being added to the state.

Then withing our if condition, if it's true we can add the tag entered by the user using our setTags() function. you'll notice that I'm using the spread operator(...tags) here to to first add the tags we already have and then add on the tag the user just entered. This syntax just makes sure that incoming tags are added in the last of the tags array and finally we're clearing out the value from our input tag so the user can enter the new one.

Remove tags functionality

To remove a tag, the user can click on the close icon that all the tags have. I'm passing a onClick event handler to handle the remove tag functionality.



// TagsInput.jsx
...
{tags.map((tag, index) => (
    <li key={index}>
        <span>{tag}</span>
        <i
            className="material-icons"
            onClick={() => removeTags(index)} 
        >
            close
        </i>
    </li>
))}
...


Enter fullscreen mode Exit fullscreen mode

We're returning a removeTags() when the user click on close icon and passing the index of the tag that's been clicked to remove. Now right below our addTags(), we'll add removeTags().



// TagsInput.jsx
...
const addTags = event => {
    ...
};
const removeTags = index => {
    setTags([...tags.filter(tag => tags.indexOf(tag) !== index)]);
};
...


Enter fullscreen mode Exit fullscreen mode

Since we're passing the index of the tag that the user wants to remove, we can use filter() method to remove the tag based on it's index. On the line no. 8 in above code, we're simply iterating our tags array and looking for a tag whose index matches the index of the tag the user wants to remove, once it's found it'll be filtered out and rest of the tags will remain in the resulting array. Finally we're using the spread operator again to pass in the resulting tags in an array and then use setTags() to update the state.

Let's Import TagsInput component into our base component



// index.js
import React from "react";
import ReactDOM from "react-dom";
import "./styles.scss";

import TagsInput from './TagsInput';

const App = () => {
    return (
        <div className="App">
            <TagsInput />
        </div>
    );
};

ReactDOM.render(<App />, document.getElementById("root"));


Enter fullscreen mode Exit fullscreen mode

Now how do we get the tags that the user added into our base component. We'll declare a function called selectedTags in our base component that we'll pass as props to our TagsInput component.



...
const App = () => {
    const selectedTags = tags => console.log(tags)};
    return (
        <div className="App">
            <TagsInput selectedTags={selectedTags}/>
        </div>
    );
};
...


Enter fullscreen mode Exit fullscreen mode

From our TagsInput component, we can now call the selectedTags method and pass the tags array to our base component.



// TagsInput.jsx
...
const TagsInput = props => {
    const [tags, setTags] = React.useState([]);
    const addTags = event => {
        if (event.key === "Enter" && event.target.value !== "") {
            setTags([...tags, event.target.value]);
            props.selectedTags([...tags, event.target.value]);
            event.target.value = "";
        }
    };
    ...
};


Enter fullscreen mode Exit fullscreen mode

You'll notice that we've passed props as parameter to our TagsInput component. We'll be using it to access the selectedTags() that we passed from the base component. On line no. 9 in above code, We're calling the selectedTags() method and passing in the same arguments as the setTags on line no. 8. Notice that I'm not passing the tags itself that we destructured from useState to avoid passing the older tags array.

Now whenever the user add a new tag, the base component will have the access to update tags array.

Codepen Demo


Thanks for reading, this is my first blogpost here - any feedback is most welcome!(https://www.prvnbist.com/blog/create-a-tags-input-component-in-react)!

Top comments (15)

Collapse
 
mcusack60 profile image
mcusack60 • Edited

Nice tutorial! Easy to follow. Have a question on this:
Has anyone used this but added functionality to find existing values of tags (from a database, for example. I don't need help with the fetching the values) and present those as options to select from?

-Mike

Collapse
 
prvnbist profile image
Praveen Bisht

Not sure but to extend this with such functionality one just have to listen to input and and display the matching options in dropdown and on select push the selected option to the tags list.

Let me know if you need help with this.

Collapse
 
debrajhyper profile image

Hey, Thanks for the awsome explanation, is there a way to fix the addTags functionality in mobile view when there are lots of input field present after this component.

Actually in mobile view if there are many field present after the TagsInput component then "Enter" key is behaving like "Tab" to focus on the next input field.

Collapse
 
prvnbist profile image
Praveen Bisht

Thanks for your input, I'll try to reproduce and fix it

Collapse
 
debrajhyper profile image
Debraj Karmakar

Looking forward for your solution. ☺

Collapse
 
gvinod1991 profile image
Vinod Godti

Great one

Collapse
 
singhayush profile image
singh-ayush

Hey, Nice tutorial, is there any way we can add a max tag limit to this

Collapse
 
prvnbist profile image
Praveen Bisht

yea, you can set the limit check in addTags function and also disable input field if tag limit has been reached.

Collapse
 
joaovmvini profile image
joaovmvini

Nice article, thanks for sharing! I have build one, check it out: jsuites.net/v3/javascript-tags

Collapse
 
atiarbshhi profile image
AtiArbshhi

Hi,

I used your tutorial to create tags, but when I refresh the page, the tags will not stay and will disappear. Can you help me with this?

Collapse
 
prvnbist profile image
Praveen Bisht

You would have to persist the tags by storing in some database or local storage, whichever works with your usecase

Collapse
 
tarcianodias profile image
Tarciano Dias

Welsome article, good job!!

Collapse
 
laurosca profile image
laurosca • Edited

Nice article!
Also you can add flex: 1; to the input for a full width or remaining space clickable area.

Collapse
 
prvnbist profile image
Praveen Bisht

Sweet, that works wonders!

Collapse
 
hafizfarooq78690 profile image
Hafiz Muhammad Farooq

good job man