JSFiddle - React, Tailwind, and code Playground

by nickcoutsos

HTML

<body>

</body>

CSS

.chip-input {
  font-family: avenir;
  display: inline-block;
  border: 1px solid gray;
  border-radius: 4px;
  cursor: text;
}

.chip-input input {
  font-family: avenir;
  display: inline;
  border: none;
  outline: none;
  padding: 0;
  margin: 0;
}

.chip-input .chip {
  display: inline-block;
  padding: 4px;
  margin: 2px;
  border-radius: 4px;
  font-family: avenir;
  background-color: #910e0e;
  color: white;
}

.chip.selected {
  background-color: #914e0e
}

JavaScript

function chipInput (initialValues) {
	const input = document.createElement('input')
  const holder = document.createElement('div')
  const chips = []
  let selected = null

  holder.classList.add('chip-input')
  holder.appendChild(input)
  
  input.addEventListener('keydown', e => {
  	if (e.code === 'Enter' && input.value.trim().length > 0) {
    	addChip(input.value)
      input.value = ''
      e.preventDefault()
    } else if (e.code === 'Backspace' && input.value.length === 0) {
    	if (selected) {
      	removeChip(selected)
      }

			selectChip(chips[chips.length - 1])
    } else {
    	selectChip(null)
    }
  })
  
  function addChip (value) {
    const chip = document.createElement('span')
    chip.classList.add('chip')
    chip.textContent = value.trim()
    chips.push(chip)
    holder.insertBefore(chip, input)
  }
  
  function removeChip (chip) {
  	chips.splice(chips.indexOf(chip), 1)
    holder.removeChild(chip)
  }
  
  function selectChip (chip) {
    selected = chip
  	chips.forEach(chip => chip.classList.remove('selected'))
    chip && chip.classList.add('selected')
  }
  
  for (let value of initialValues) {
  	addChip(value)
  }

  return {
    element: holder
  }
}

const cinput = chipInput(['foo', 'bar'])
document.body.appendChild(cinput.element)
cinput.element.focus()