<div class="input-group">
  <span class="input-group__cell">
    <input class="input-group__input" type="number">
    <span class="input-group__text"></span>
  </span>

  <span class="input-group__cell">
    <input class="input-group__input" type="number">
    <span class="input-group__text"></span>
  </span>

  <span class="input-group__cell">
    <input class="input-group__input" type="number">
    <span class="input-group__text"></span>
  </span>

  <span class="input-group__cell">
    <input class="input-group__input" type="number">
    <span class="input-group__text"></span>
  </span>

</div>
* {
  box-sizing: border-box;
}

body {
  display: flex;
  justify-content: center;
  align-items: center;
  margin: 0;
  height: 100vh;
  background-color: #00010a;
}

.input-group {
  display: flex;
  justify-content: center;
  font-size: 2rem;
  font-family: sans-serif;
}

.input-group__cell {
  position: relative;
  width: 1.75em;
  flex-shrink: 0;
  overflow: hidden;
}

.input-group__cell:not(:last-child) {
  margin-right: 0.5em;
}

.input-group__input {
  width: 100%;
  margin: 0;
  padding: 0.25em;
  font: inherit;
  text-align: center;
  appearance: none;
  background-color: transparent;
  color: transparent;
  border: 2px solid #202660;
  border-radius: 5px;
  -moz-appearance: textfield;
}

.input-group__input:focus {
  border: 2px solid #9d2183;
  outline: none;
}

.input-group__input::-webkit-outer-spin-button,
.input-group__input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.input-group__text {
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  inset: 0;
  color: #ccc;
  pointer-events: none;
  transform: translateY(100%);
}

.input-group__text.show {
  transform: translateY(0);
  transition: transform 350ms cubic-bezier(0.18, 0.89, 0.32, 1.28);
}
const nextFrame = (fn) => requestAnimationFrame(() => requestAnimationFrame(fn));

const inputGroup = document.querySelector('.input-group');

const inputCells = Array.from(
  inputGroup.querySelectorAll('.input-group__cell'),
  (el, index) => ({
    index,
    cell: el,
    input: el.querySelector('.input-group__input'),
    text: el.querySelector('.input-group__text'),
  })
);

inputGroup.addEventListener('input', (event) => {
  const cellGroup = inputCells.find(c => c.input === event.target);
  const { index, text } = cellGroup;

  const value = Number(event.data);
  const hasValue = !Number.isNaN(value) && event.data !== null;

  text.textContent = hasValue ? value : '';
  event.target.value = hasValue ? value : '';
  
  if (hasValue) {
    text.classList.remove('show');
    nextFrame(() => text.classList.add('show'));
    
    if (index >= inputCells.length - 1) {
      event.target.blur();
    }
    else {
      inputCells[index + 1].input.focus();
    }
  }
});

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.