Alpine number clamp

Simple demo to show an element with with Alpine.js

by James Doyle

HTML

<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
<script>
  // has to be defined here in order to work
  window.Alpine.magic("clamp", () => {
    return (number, min, max) => {
      // Ensure min is the lower bound and max is the upper bound, regardless of input order
      const lower = Math.min(min, max)
      const upper = Math.max(min, max)
      // Clamp the number
      return Math.min(Math.max(Number(number), lower), upper)
    }
  })
</script>

<!-- default value is 4 -->
<!-- when letters are entered (nan) we set it to the min -->
<div
  x-data="{ value: 4, min: 1, max: 11 }"
  x-effect="value = isNaN(value) ? min : $clamp(value, min, max)"
  class="~px-1/3 flex items-stretch justify-center"
>
  <button
    title="Increase product quantity"
    type="button"
    class="px-1 disabled:cursor-not-allowed disabled:opacity-50"
    x-on:click="value = value + 1"
    x-bind:disabled="value === max"
  >
    +
  </button>
  <input
    name="quantity"
    title="Product quantity"
    type="text"
    inputmode="numeric"
    pattern="[1-9]{1,2}"
    x-model.number="value"
    x-bind:min="min"
    x-bind:max="max"
    step="1"
    class="h-full w-8 appearance-none border-none p-0 text-center"
  />
  <button
    title="Decrease product quantity"
    type="button"
    class="px-1 disabled:cursor-not-allowed disabled:opacity-50"
    x-on:click="value = value - 1"
    x-bind:disabled="value === min"
  >
    -
  </button>
</div>