JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/mithril/0.2.5/mithril.min.js"></script>
<h4>自動補完2</h4>
<div id="root"></div>

SCSS

.filterInput {  
    display: inline-block; 
    box-shadow: 0 1px 1px rgba(160,160,160,0.2) inset;
    border-width: 1px;
   
    border-style: solid;
    border-color: #c8c8c8;
    border-radius: 3px;

    position: relative;
    padding: 2px;
    background-color: #ffffff;

    .currentFilters {
        display: inline-block;
        list-style-type: none;
        padding: 0px;
        margin: 0px;
        li {
            display: inline-block;
            margin: 0px 3px;
            padding: 0px 3px;
            border-radius: 2px;
            background-color: #d9eafe!important;
            box-shadow: 0 0 0 1px #c0dcfd;

            a {
                margin: 0px 3px;
            }
        }
    }
    .form {
        margin: 2px;
        display: inline-block;
        input {
            border-style: none;
        }
        .suggestions {
            position: absolute;
            background-color: #eeeeee;
            box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
            z-index: 1000;

            list-style-type: none;

            padding: 10px;
            margin: 0px;

            .selected {
                background-color: #d9eafe;
            }
        }
    }
}

JavaScript

'use strict';

// Based on https://gist.github.com/StephanHoyer/ea6d1e9c5ea7a9225639

// ヘルパー関数
function last(array) {
    return array.slice(-1)[0];
}

function remove(array, filter) {
    const index = array.indexOf(filter);
    if (index !== -1) {
        array.splice(index, 1);
    }
}

const code = {
    enter: 13,
    backspace: 8,
    del: 46,
    left: 37,
    up: 38,
    right: 39,
    down: 40
};

function sameAs(filterA) {
  return function (filterB) {
    return filterA.type === filterB.type && filterA.label === filterB.label;
  };
}

function not(fn) {
  return function(obj) {
    return !fn(obj);
  };
}

function emptyArrayFn() {
  return [];
}

function minMax(a, b, c) {
  return Math.max(a, Math.min(b, c));
}

// 補完コンポーネント
const FilterInput = {
  controller: function (options) {
    var scope = {};
    options = options || {};
    options.getSuggestions = options.getSuggestions || emptyArrayFn;
    options.getCurrentFilters = options.getCurrentFilters || emptyArrayFn;
    scope.currentFilters = options.getCurrentFilters;
    scope.inputValue = '';

    function exists(filter) {
      return scope.currentFilters().some(sameAs(filter));
    }

    function updateSuggestions() {
      if (scope.inputValue) {
        scope.suggestions = options.getSuggestions(scope.inputValue).filter(not(exists));
      } else {
        scope.suggestions = [];
      }
    }
    updateSuggestions();

    scope.oninput = function (event) {
      scope.inputValue = event.target.value;
      delete scope.selectedSuggestion;
      delete scope.selectedFilter;
      updateSuggestions();
    };

    scope.add = function (filter) {
      return function () {
        if (!exists(filter)) {
          scope.currentFilters().push(filter);
          options.onAddFilter && options.onAddFilter(filter);
          scope.inputValue = '';
          updateSuggestions();
        }
      };
    };

    scope.remove = function (filter) {
      return function () {
       ...