Tags input with React

ยท

5 min read

Tags input, a trending component widely used on the web nowadays. In this blog, I will show you some of the steps to set up your own tags input component using React. A sample of the final product is shown below.

The <TagInput> component is made out of a <div> which contains a series of <span> elements listing the tags, and an <input> of type "text" where the new tags are added. The <TagsInput> component contains one method to add the tags and another one to delete them. Let's start defining the jsx that is returned from the component.

<div className="tags-input">
   {this.state.tags.map((tag,index) => {
      return (
         <span key={index} className="tag mr-1 mb-1 badge bg-primary">
            {tag} 
            <span className="tag-remove" 
               onClick={() => this.removeTag(index)}>
            </span>
         </span>
      )})
   }
   <input 
      value={this.state.newTag} 
      onChange={(e) => this.setState({newTag: e.target.value})} 
      onKeyDown={e => this.handleTag(e)} 
      type="text"
      size="7"
      placeholder="New Tag" 
      className="text-input" 
   />
</div>

The <input> triggers the handleTag whenever a key is pressed, this method checks whether the user pressed the enter key and if the current value is valid. If the conditions are meet the new tag is pushed into the tags array and the state is updated.

handleTag = (e) => {
   const target = e.target;
   e.keyCode === 13 && e.preventDefault();
   if (e.keyCode === 13 && target.value && target.value.trim().length){
      const tags = this.state.tags;
      tags.push(target.value);
      this.setState({tags, newTag: ''});
      this.props.onChange(this.state.tags);
      target.size = 7;
   }
   if(target.value.length > 6){
      target.size++;
   }
}

The prop onChange sets the communication with the parent of the <TagInput> component. If no prop is sent the component might shot an error, thereby, adding default props is recommended.

TagInput.defaultProps = {
   onChange: ((tags)=> console.log(tags)),
   tags: []
}

Now that our component is able to add tags let's focus on delete them. Let's have a better look at the map function used to populate the <TagInput> component.

{this.state.tags.map((tag,index) => {
      return (
         <span key={index} className="tag mr-1 mb-1 badge bg-primary">
            {tag} 
            <span className="tag-remove" 
               onClick={() => this.removeTag(index)}>
            </span>
         </span>
    )})
}

In here, a <span> is created for each value of the tabs array, and inside of them, another <span> is assigned to trigger the removeTag method.

removeTag = (index) => {
     let tags = this.state.tags;
     tags.splice(index,1);
     this.setState({ tags });
     this.props.onChange(this.state.tags);
}

By now you should already have a working component. You can find the CSS and the whole component in the codepen I made.

Finally, an extra feature. If you want the tag to be added once the user leaves the component you could make use of the react-outside-click-handler. The first step is to import the package using the following command.

$ npm install react-outside-click-handler

Once the package is installed, import the component into your file by using import OutsideClickHandler from 'react-outside-click-handler'. With the package set up, wrap the initial jsx into an <OutsideClickHandler> component as follows.

<OutsideClickHandler
   onOutsideClick={() => { this.onOutsideClickAdd();}}
>
   {/* ALL THE PREVIOUS JSX*/}
</OutsideClickHandler>

Lastly, let's add the onOutsideClickAdd method which pushes the new tag (if valid) into the tags array once the user clicks outside the <TagInput> component.

onOutsideClickAdd = () => {
   if (this.state.newTag.trim().length){
      const tags = this.state.tags;
      tags.push(this.state.newTag);
      this.setState({tags, newTag: ''});
      this.props.onChange(this.state.tags);
   }
}

I hope you find this information useful and thanks for reading.



Always yours,

Carlitos xoxo ๐Ÿ˜˜