<main>
  <p>Separate your tags with a comma</p>
  <div class="tags-input"></div>
  <h1><span>Tags</span> Input</h1>
</main>
$white: #fff
$blue: #71ccd5
$dark-grey: #888
$grey: #bbb
$light-grey: #dfdfdf

html, body, main
  height: 100%

main
  max-width: 500px
  margin: 0 auto
  padding: 0 30px
  display: flex
  flex-direction: column-reverse
  justify-content: center
  font-family: 'Open Sans', Helvetica, Arial, sans-serif

h1
  margin-bottom: 20px
  font-size: 20px
  font-weight: 300
  text-align: center
  text-transform: uppercase
  letter-spacing: 5px
  color: $grey
  span
    border: 2px solid $light-grey
    padding: 3px 2px 3px 7px
    border-radius: 6px
    font-weight: 400

p
  margin-top: 10px
  font-size: 10px
  font-weight: bold
  color: $blue
  text-align: center
  text-transform: uppercase
  letter-spacing: 1px

.tags-input
  border: 2px solid $light-grey
  border-radius: 40px
  height: 40px
  padding: 0 11px
  font-size: 14px
  display: flex
  align-items: center
  overflow: hidden
  color: $dark-grey
  span
    background: $grey
    margin-right: 7px
    color: $white
    padding: 4px 7px
    border-radius: 20px
    &[data-selected]
      background: $blue
  &::after
    content: ''
    background: $dark-grey
    width: 1px
    height: 19px
    margin: -1px 0 0 -1px
    display: none
    animation: blink 0.5s infinite alternate
  &:focus
    border-color: $blue
    outline: none
    &[data-cursor]::after
      display: block
      @media screen and (max-width: 736px)
        display: none
    + h1
      color: $blue
      span
        border-color: $blue

@keyframes blink
  0%
    opacity: 1
  49%
    opacity: 1
  50%
    opacity: 0
  100%
    opacity: 0
View Compiled
var TagsInput = function(element) { 
  var self = this;
  var initChar = "\u200B";
  var initCharPattern = new RegExp(initChar, 'g');
  
  var insert = function(element) {
     if(self.textNode) self.element.insertBefore(element, self.textNode);
     else self.element.appendChild(element);
  };
  
  var updateCursor = function() {
    self.cursor = self.blank;
  };
  
  var keydown = function(event) {
    if(event.keyCode == 188) {
      event.preventDefault();
      setTimeout(function() {
        var text = self.text;
        if(text) {
          self.text = initChar;
          self.add(text);
        }
      }, 1);
    }
    else if(event.keyCode == 8) {
      if(self.text.replace(initCharPattern, '') == '') {
        self.text = initChar+initChar;
        if(self.selected) {
          self.element.removeChild(self.selected);
        }
        else {
          var tags = self.tags;
          var keys = Object.keys(tags)
          if(keys.length > 0) {
            var tag = tags[keys[keys.length-1]];
            tag.setAttribute('data-selected', '');
          }
        }
      }
    }
    
    if(event.keyCode !== 8) {
      if(self.selected) self.selected.removeAttribute('data-selected');
    }
    setTimeout(function() {
      updateCursor();
    }, 1);
  };
  
  var focus = function() {
    updateCursor();
  };
  
  Object.defineProperties(this, {
    element: {
      get: function() {
        return element;
      },
      set: function(v) {
        if(typeof v == 'string') v = document.querySelector(v);
        element = v instanceof Node ? v : document.createElement('div');
        if(!element.className.match(/\btags-input\b/)) element.className += ' tags-input';
        if(element.getAttribute('contenteditable') != 'true') element.setAttribute('contenteditable', 'true');
        
        element.removeEventListener('keydown', keydown);
        element.addEventListener('keydown', keydown);
        
        element.removeEventListener('focus', focus);
        element.addEventListener('focus', focus);
        this.text = initChar;
      }
    },
    tags: {
      get: function() {
        var element;
        var elements = this.element.querySelectorAll('span');
        var tags = {};
        for(var i = 0; i < elements.length; i++) {
          element = elements[i]
          tags[element.innerText] = element;
        }
        
        return tags;
      }
    },
    lastChild: {
      get: function() {
        return this.element.lastChild;
      }
    },
    textNode: {
      get: function() {
        return this.element.lastChild instanceof Text ? this.element.lastChild : null;
      }
    },
    text: {
      get: function() {
        return this.textNode ? this.textNode.data : null;
      },
      set: function(v) {
        if(!this.textNode) this.element.appendChild(document.createTextNode(','));
        this.textNode.data = v;
      },
    },
    cursor: {
      get: function() {
        return this.element.getAttribute('data-cursor') !== null;
      },
      set: function(v) {
        if(v) this.element.setAttribute('data-cursor', '');
        else this.element.removeAttribute('data-cursor');
      }
    },
    focused: {
      get: function() {
        return document.activeElement == this.element;
      }
    },
    blank: {
      get: function() {
        return this.text.replace(initCharPattern, '') == '';
      }
    },
    selected: {
      get: function() {
        return this.element.querySelector('span[data-selected]');
      }
    }
  });
  
  this.add = function(tag) {
    tag = tag.replace(initCharPattern, '');
    tag = tag.replace(/^\s+/, '').replace(/\s+$/, '');
    tag = tag[0].toUpperCase()+tag.toLowerCase().slice(1);
    if(tag != '' && this.tags[tag] === undefined) {
      var element = document.createElement('span');
      element.appendChild(document.createTextNode(tag));
      element.setAttribute('contenteditable', 'false');
      
      insert(element);
    }
  };
  
  this.remove = function(tag) {
     var element = this.tags[tag];
     if(element) this.element.removeChild(element);
  };
  
  this.element = element;
};

var input = new TagsInput('.tags-input');

External CSS

  1. https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700,800

External JavaScript

This Pen doesn't use any external JavaScript resources.