Back to CSS Tags & Chips Tag Input Light JS
Share
.ctc-input { position: relative; display: flex; flex-wrap: wrap; align-items: center; gap: 6px; padding: 6px 8px; width: 280px; background: #15151d; border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; }

.ctc-input:focus-within { border-color: #7c6cff; }

.ctc-input-chips { display: contents; list-style: none; margin: 0; padding: 0; }

.ctc-input-chips li { display: inline-flex; align-items: center; gap: 4px; padding: 3px 6px 3px 10px; background: rgba(124,108,255,0.18); color: #c4b5fd; border-radius: 4px; font: 600 11px/1 system-ui, sans-serif; }

.ctc-input-chips button { background: transparent; border: 0; padding: 0; width: 16px; height: 16px; color: inherit; cursor: pointer; font-size: 14px; line-height: 1; }

.ctc-input-field { flex: 1; min-width: 60px; background: transparent; border: 0; outline: none; color: #f0eeff; font: 500 12px/1 system-ui, sans-serif; padding: 4px 0; }

.ctc-input-field::placeholder { color: #b8b6d4; }

.ctc-input-list { position: absolute; top: calc(100% + 4px); left: 0; right: 0; margin: 0; padding: 4px; list-style: none; background: #15151d; border: 1px solid rgba(255,255,255,0.1); border-radius: 8px; z-index: 5; max-height: 160px; overflow: auto; }

.ctc-input-list[hidden] { display: none; }

.ctc-input-list li { padding: 6px 10px; border-radius: 4px; font: 500 12px/1 system-ui, sans-serif; color: #c4b5fd; cursor: pointer; }

.ctc-input-list li:hover, .ctc-input-list li[aria-selected="true"] { background: rgba(124,108,255,0.18); color: #fff; }
<div class="ctc-input">
  <ul class="ctc-input-chips" role="list"></ul>
  <input type="text" class="ctc-input-field"
    placeholder="Type a language…"
    aria-label="Add a language tag"
    aria-controls="ctc-input-list"
    aria-expanded="false"
    autocomplete="off" />
  <ul class="ctc-input-list" id="ctc-input-list" role="listbox" hidden></ul>
</div>
(function () {
  var SUGGESTIONS = ['JavaScript','TypeScript','Python','Go','Rust','Ruby','Swift','Kotlin','Java','C++','Elixir','Haskell'];
  document.querySelectorAll('.ctc-input').forEach(function (root) {
    var chipsEl = root.querySelector('.ctc-input-chips');
    var input   = root.querySelector('.ctc-input-field');
    var listEl  = root.querySelector('.ctc-input-list');
    var chips = [];
    function render() {
      chipsEl.innerHTML = '';
      chips.forEach(function (c, i) {
        var li  = document.createElement('li');
        var txt = document.createElement('span');
        txt.textContent = c;
        var btn = document.createElement('button');
        btn.type = 'button';
        btn.setAttribute('aria-label', 'Remove ' + c);
        btn.textContent = '×';
        btn.addEventListener('click', function () { chips.splice(i, 1); render(); });
        li.appendChild(txt); li.appendChild(btn);
        chipsEl.appendChild(li);
      });
    }
    function showList(items) {
      if (!items.length) { listEl.setAttribute('hidden',''); input.setAttribute('aria-expanded','false'); return; }
      listEl.innerHTML = '';
      items.forEach(function (s) {
        var li = document.createElement('li');
        li.setAttribute('role','option');
        li.textContent = s;
        li.addEventListener('mousedown', function (e) {
          e.preventDefault();
          if (chips.indexOf(s) === -1) chips.push(s);
          input.value = ''; render(); showList([]);
        });
        listEl.appendChild(li);
      });
      listEl.removeAttribute('hidden');
      input.setAttribute('aria-expanded','true');
    }
    input.addEventListener('input', function () {
      var q = input.value.trim().toLowerCase();
      if (!q) { showList([]); return; }
      var matches = SUGGESTIONS.filter(function (s) {
        return s.toLowerCase().includes(q) && chips.indexOf(s) === -1;
      }).slice(0, 6);
      showList(matches);
    });
    input.addEventListener('keydown', function (e) {
      if (e.key === 'Enter') {
        e.preventDefault();
        var v = input.value.trim();
        if (v && chips.indexOf(v) === -1) { chips.push(v); input.value = ''; render(); showList([]); }
      } else if (e.key === 'Backspace' && !input.value && chips.length) {
        chips.pop(); render();
      } else if (e.key === 'Escape') {
        showList([]);
      }
    });
    input.addEventListener('blur', function () { setTimeout(function () { showList([]); }, 150); });
  });
})();
Live preview Edit any tab — preview updates live Ready