Back to CSS Button Groups Synthwave Dial Light JS
Share
HTML
<div class="cbgp-syn" role="group" aria-label="Quantity">
  <button type="button" data-cbgp-syn-step="-1" aria-label="Decrease quantity">−</button>
  <input type="number" min="1" max="10" value="1" aria-label="Quantity" data-cbgp-syn />
  <button type="button" data-cbgp-syn-step="1" aria-label="Increase quantity">+</button>
</div>
CSS
.cbgp-syn {
  display: inline-flex; align-items: stretch;
  background: linear-gradient(180deg, #0a0a14 0%, #050810 100%);
  border: 1px solid #ff5af1;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: 0 0 14px rgba(255,90,241,0.25);
}
.cbgp-syn button {
  width: 42px; height: 42px;
  border: 0; cursor: pointer;
  background:
    linear-gradient(180deg, rgba(255,255,255,0.08), transparent),
    rgba(8,10,18,0.92);
  color: #ff5af1;
  font: 800 18px/1 ui-monospace, monospace;
  text-shadow: 0 0 6px rgba(255,90,241,0.6);
  transition: background 0.18s, color 0.18s;
}
.cbgp-syn button:hover {
  background: rgba(255,90,241,0.12);
  color: #ffaaf0;
}
.cbgp-syn button:focus-visible { outline: 2px solid #00ffe0; outline-offset: -2px; }
.cbgp-syn button:disabled { opacity: 0.3; cursor: not-allowed; }
.cbgp-syn button:disabled:hover { background: rgba(8,10,18,0.92); color: #ff5af1; }
.cbgp-syn input {
  width: 64px;
  border: 0; outline: none;
  background:
    repeating-linear-gradient(0deg,
      transparent 0 4px,
      rgba(0,255,224,0.06) 4px 5px),
    #0a0a14;
  color: #00ffe0;
  font: 800 16px/1 ui-monospace, monospace;
  text-align: center;
  text-shadow: 0 0 6px rgba(0,255,224,0.5);
  border-left: 1px solid rgba(255,90,241,0.3);
  border-right: 1px solid rgba(255,90,241,0.3);
  -moz-appearance: textfield;
}
.cbgp-syn input::-webkit-outer-spin-button,
.cbgp-syn input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.cbgp-syn.is-min input { color: #00ffe0; box-shadow: inset 0 0 16px rgba(0,255,224,0.3); }
.cbgp-syn.is-max input { color: #ff5af1; box-shadow: inset 0 0 16px rgba(255,90,241,0.4); }
JS
/* Synthwave-stepper — clamp + classify min/max state for color shift. */
document.querySelectorAll('.cbgp-syn').forEach(function (group) {
  var input = group.querySelector('[data-cbgp-syn]');
  var minus = group.querySelector('[data-cbgp-syn-step="-1"]');
  var plus  = group.querySelector('[data-cbgp-syn-step="1"]');
  if (!input) return;
  function update() {
    var min = Number(input.min) || -Infinity;
    var max = Number(input.max) ||  Infinity;
    var val = Number(input.value) || 0;
    if (minus) minus.disabled = val <= min;
    if (plus)  plus.disabled  = val >= max;
    group.classList.toggle('is-min', val <= min);
    group.classList.toggle('is-max', val >= max);
  }
  group.querySelectorAll('[data-cbgp-syn-step]').forEach(function (btn) {
    btn.addEventListener('click', function () {
      var dir = parseInt(btn.dataset.cbgpSynStep, 10) || 0;
      var min = Number(input.min) || -Infinity;
      var max = Number(input.max) ||  Infinity;
      var val = (Number(input.value) || 0) + dir;
      input.value = String(Math.max(min, Math.min(max, val)));
      update();
    });
  });
  input.addEventListener('input', update);
  update();
});