Input Number
數量選擇器 — [−] [input] [+] 3 元素邊框連結。min/max/step 同時由 HTML 屬性和 Alpine 鉗制強制,達邊界時 ± 按鈕自動停用。原生旋轉箭頭隱藏。支援小數 step (如 0.5)。
最簡 — name + label + min/value
<x-input-number name="quantity" label="Quantity" :value="1" :min="1" />
<div class="inline-flex flex-col" x-data="{ v: '1', min: 1, max: null, step: 1, disabled: false, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<label for="quantity_6a717cd5a6a1d" class="block mb-1.5 text-[length:var(--text-field-sm)] font-medium text-base-content">Quantity</label>
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="quantity_6a717cd5a6a1d" x-model="v" x-bind:disabled="disabled" size="3" name="quantity" min="1" step="1" inputmode="numeric" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-md)] text-[length:var(--text-field-md)]">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
</div>
bounded with step — min=1, max=8
1 to 8 seats
<x-input-number
name="seats" label="Number of seats"
:value="2" :min="1" :max="8" :step="1"
hint="1 to 8 seats" />
<div class="inline-flex flex-col" x-data="{ v: '2', min: 1, max: 8, step: 1, disabled: false, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<label for="seats_6a717cd5b267f" class="block mb-1.5 text-[length:var(--text-field-sm)] font-medium text-base-content">Number of seats</label>
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="seats_6a717cd5b267f" x-model="v" x-bind:disabled="disabled" size="3" name="seats" min="1" max="8" step="1" inputmode="numeric" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-md)] text-[length:var(--text-field-md)]">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
<p class="mt-1.5 text-[length:var(--text-field-sm)] text-base-content/50">
1 to 8 seats
</p>
</div>
decimal step — value=3.5, step=0.5
<x-input-number name="score" label="Score" :value="3.5" :min="0" :max="5" :step="0.5" width="w-40" />
<div class="w-40" x-data="{ v: '3.5', min: 0, max: 5, step: 0.5, disabled: false, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<label for="score_6a717cd5be1f1" class="block mb-1.5 text-[length:var(--text-field-sm)] font-medium text-base-content">Score</label>
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="score_6a717cd5be1f1" x-model="v" x-bind:disabled="disabled" name="score" min="0" max="5" step="0.5" inputmode="numeric" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-md)] text-[length:var(--text-field-md)] flex-1">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
</div>
size — xs / sm / md (default) / lg
<x-input-number size="xs" :value="3" :min="0" :max="10" />
<x-input-number size="sm" :value="3" :min="0" :max="10" />
<x-input-number size="md" :value="3" :min="0" :max="10" />
<x-input-number size="lg" :value="3" :min="0" :max="10" />
<div class="inline-flex flex-col" x-data="{ v: '3', min: 0, max: 10, step: 1, disabled: false, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-xs)] h-[var(--h-field-xs)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="inputnum_6a717cd5c8bbc" x-model="v" x-bind:disabled="disabled" size="3" min="0" max="10" step="1" inputmode="numeric" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-xs)] text-[length:var(--text-field-xs)]">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-xs)] h-[var(--h-field-xs)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
</div>
<div class="inline-flex flex-col" x-data="{ v: '3', min: 0, max: 10, step: 1, disabled: false, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-sm)] h-[var(--h-field-sm)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="inputnum_6a717cd5c8c21" x-model="v" x-bind:disabled="disabled" size="3" min="0" max="10" step="1" inputmode="numeric" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-sm)] text-[length:var(--text-field-sm)]">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-sm)] h-[var(--h-field-sm)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
</div>
<div class="inline-flex flex-col" x-data="{ v: '3', min: 0, max: 10, step: 1, disabled: false, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="inputnum_6a717cd5c8c79" x-model="v" x-bind:disabled="disabled" size="3" min="0" max="10" step="1" inputmode="numeric" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-md)] text-[length:var(--text-field-md)]">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
</div>
<div class="inline-flex flex-col" x-data="{ v: '3', min: 0, max: 10, step: 1, disabled: false, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-lg)] h-[var(--h-field-lg)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="inputnum_6a717cd5c8ccb" x-model="v" x-bind:disabled="disabled" size="3" min="0" max="10" step="1" inputmode="numeric" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-lg)] text-[length:var(--text-field-lg)]">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-lg)] h-[var(--h-field-lg)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
</div>
error state
At least 1 required
<x-input-number name="qty" label="Quantity" :value="0" :min="1" error="At least 1 required" />
<div class="inline-flex flex-col" x-data="{ v: '0', min: 1, max: null, step: 1, disabled: false, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<label for="qty_6a717cd5efc99" class="block mb-1.5 text-[length:var(--text-field-sm)] font-medium text-error">Quantity</label>
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="qty_6a717cd5efc99" x-model="v" x-bind:disabled="disabled" size="3" name="qty" min="1" step="1" inputmode="numeric" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-md)] text-[length:var(--text-field-md)]">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
<p class="mt-1.5 text-[length:var(--text-field-sm)] text-error">
At least 1 required
</p>
</div>
disabled
Disabled inputs cannot be stepped
<x-input-number label="Read only" :value="42" disabled hint="Disabled inputs cannot be stepped" />
<div class="inline-flex flex-col" x-data="{ v: '42', min: null, max: null, step: 1, disabled: true, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<label for="inputnum_6a717cd60699c" class="block mb-1.5 text-[length:var(--text-field-sm)] font-medium text-base-content">Read only</label>
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="inputnum_6a717cd60699c" x-model="v" x-bind:disabled="disabled" size="3" step="1" inputmode="numeric" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-md)] text-[length:var(--text-field-md)]">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
<p class="mt-1.5 text-[length:var(--text-field-sm)] text-base-content/50">
Disabled inputs cannot be stepped
</p>
</div>
width override (default 會被限制在 max-w-[10rem])
<x-input-number name="price" label="Custom price" :value="100" :min="0" :step="100" width="w-full" />
<div class="w-full" x-data="{ v: '100', min: 0, max: null, step: 100, disabled: false, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<label for="price_6a717cd611562" class="block mb-1.5 text-[length:var(--text-field-sm)] font-medium text-base-content">Custom price</label>
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="price_6a717cd611562" x-model="v" x-bind:disabled="disabled" name="price" min="0" step="100" inputmode="numeric" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-md)] text-[length:var(--text-field-md)] flex-1">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
</div>
no label / no chrome — compact
<x-input-number :value="1" :min="0" :max="99" />
<x-input-number :value="5" :min="0" :max="99" size="sm" />
<x-input-number :value="10" :min="0" :max="99" size="xs" />
<div class="inline-flex flex-col" x-data="{ v: '1', min: 0, max: 99, step: 1, disabled: false, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="inputnum_6a717cd61bdee" x-model="v" x-bind:disabled="disabled" size="3" min="0" max="99" step="1" inputmode="numeric" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-md)] text-[length:var(--text-field-md)]">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
</div>
<div class="inline-flex flex-col" x-data="{ v: '5', min: 0, max: 99, step: 1, disabled: false, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-sm)] h-[var(--h-field-sm)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="inputnum_6a717cd61be54" x-model="v" x-bind:disabled="disabled" size="3" min="0" max="99" step="1" inputmode="numeric" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-sm)] text-[length:var(--text-field-sm)]">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-sm)] h-[var(--h-field-sm)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
</div>
<div class="inline-flex flex-col" x-data="{ v: '10', min: 0, max: 99, step: 1, disabled: false, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-xs)] h-[var(--h-field-xs)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="inputnum_6a717cd61beac" x-model="v" x-bind:disabled="disabled" size="3" min="0" max="99" step="1" inputmode="numeric" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-xs)] text-[length:var(--text-field-xs)]">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-xs)] h-[var(--h-field-xs)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
</div>
Livewire model
<x-input-number name="qty" wire:model.live="qty" :min="0" :max="99" />
<div class="inline-flex flex-col" x-data="{ v: '0', min: 0, max: 99, step: 1, disabled: false, clamp(n) { if (this.min !== null && n < this.min) n = this.min; if (this.max !== null && n > this.max) n = this.max; return n; }, inc() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n + this.step; this.v = String(this.clamp(next)); }, dec() { if (this.disabled) return; const n = parseFloat(this.v); const next = isNaN(n) ? (this.min ?? 0) : n - this.step; this.v = String(this.clamp(next)); }, atMin() { return this.min !== null && parseFloat(this.v) <= this.min; }, atMax() { return this.max !== null && parseFloat(this.v) >= this.max; }, }">
<div class="inline-flex [&>*]:rounded-none [&>*:first-child]:rounded-l-[var(--radius-field)] [&>*:last-child]:rounded-r-[var(--radius-field)] [&>*:not(:last-child)]:border-r-0">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Decrease" tabindex="-1" x-on:click="dec()" x-bind:disabled="disabled || atMin()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path></svg></button>
<input type="number" id="qty_6a717cd639b8a" x-model="v" x-bind:disabled="disabled" size="3" name="qty" min="0" max="99" step="1" inputmode="numeric" wire:model.live="qty" class="min-w-[3rem] text-center tabular-nums bg-base-100 tune-border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary focus:z-10 [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none [appearance:textfield] disabled:opacity-50 disabled:cursor-not-allowed h-[var(--h-field-md)] text-[length:var(--text-field-md)]">
<button type="button" class="shrink-0 inline-flex items-center justify-center bg-base-100 tune-border border-base-300 text-base-content/70 hover:bg-base-200 hover:text-base-content transition-colors cursor-pointer focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:z-10 disabled:opacity-50 disabled:cursor-not-allowed w-[var(--h-field-md)] h-[var(--h-field-md)]" aria-label="Increase" tabindex="-1" x-on:click="inc()" x-bind:disabled="disabled || atMax()"><svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24" fill="none" stroke="currentcolor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="w-3.5 h-3.5">
<path d="M5 12h14"></path>
<path d="M12 5v14"></path></svg></button>
</div>
</div>