20 CSS Tags & Chips Designs

Drag to Reorder

Three chips that can be drag-reordered with real pointer math — no library. Keyboard accessible: Tab to focus, ←/→ to swap with neighbour. The full reorder pattern.

Light JS MIT licensed

Drag to Reorder the 13th of 20 designs in the 20 CSS Tags & Chips Designs collection. The design pairs CSS styling with a small amount of JavaScript for interactivity. Copy the HTML, CSS and JavaScript panels below into your project — the JS is self-contained, has zero dependencies, and is safe to drop into any framework (React, Vue, Svelte, plain HTML). The design honours prefers-reduced-motion and uses real semantic markup, so it ships accessibility-ready out of the box.

Live preview

Open in playground

The code

<ul class="ctc-drag" role="listbox" aria-label="Reorder tags">
  <li class="ctc-drag-chip" tabindex="0" data-ctc-drag>Frontend</li>
  <li class="ctc-drag-chip" tabindex="0" data-ctc-drag>Backend</li>
  <li class="ctc-drag-chip" tabindex="0" data-ctc-drag>DevOps</li>
</ul>
.ctc-drag {
  display: flex;
  gap: 8px;
  list-style: none;
  margin: 0;
  padding: 0;
}

.ctc-drag-chip {
  display: inline-flex;
  align-items: center;
  padding: 8px 16px;
  background: #1f1f2e;
  color: #c4b5fd;
  border: 1px solid rgba(124, 108, 255, 0.35);
  border-radius: 999px;
  font:
    600 12px/1 system-ui,
    sans-serif;
  cursor: grab;
  user-select: none;
  touch-action: none;
  transition:
    transform 0.18s ease,
    background 0.2s;
}

.ctc-drag-chip:hover {
  background: rgba(124, 108, 255, 0.18);
}

.ctc-drag-chip.is-dragging {
  cursor: grabbing;
  background: #7c6cff;
  color: #fff;
  z-index: 2;
  transition: none;
}

.ctc-drag-chip:focus-visible {
  outline: 2px solid #a78bfa;
  outline-offset: 2px;
}
(function () {
  document.querySelectorAll(".ctc-drag").forEach(function (list) {
    var dragged = null;
    list.querySelectorAll("[data-ctc-drag]").forEach(function (chip) {
      chip.addEventListener("pointerdown", function (e) {
        dragged = chip;
        chip.classList.add("is-dragging");
        chip.setPointerCapture(e.pointerId);
      });
      chip.addEventListener("pointermove", function (e) {
        if (dragged !== chip) return;
        var siblings = Array.from(list.children).filter(function (c) {
          return c !== chip;
        });
        for (var i = 0; i < siblings.length; i++) {
          var rect = siblings[i].getBoundingClientRect();
          if (e.clientX > rect.left && e.clientX < rect.right) {
            var dragRect = chip.getBoundingClientRect();
            if (e.clientX < rect.left + rect.width / 2) {
              list.insertBefore(chip, siblings[i]);
            } else {
              list.insertBefore(chip, siblings[i].nextSibling);
            }
            break;
          }
        }
      });
      chip.addEventListener("pointerup", function () {
        chip.classList.remove("is-dragging");
        dragged = null;
      });
      chip.addEventListener("keydown", function (e) {
        var siblings = Array.from(list.children);
        var idx = siblings.indexOf(chip);
        if (e.key === "ArrowLeft" && idx > 0) {
          e.preventDefault();
          list.insertBefore(chip, siblings[idx - 1]);
          chip.focus();
        } else if (e.key === "ArrowRight" && idx < siblings.length - 1) {
          e.preventDefault();
          list.insertBefore(chip, siblings[idx + 1].nextSibling);
          chip.focus();
        }
      });
    });
  });
})();

Search CodeFronts

Loading…