数量や金額、年齢のように「数字だけを入れてほしい」入力欄は、<input type="number"> で作れます。上下の矢印(スピンボタン)で値を増減でき、スマートフォンでは数字向けのキーボードが出るなど、数値入力ならではの便利さがあります。この記事では、最小値の min・最大値の max・刻み幅の step といった基本属性から、JavaScript での値の取得、スマホでのキーボード制御に使う inputmode、そして type="number" ならではの落とし穴まで、初心者の方にも分かるように解説します。
目次
type=”number” で数値入力欄を作る
数値入力欄は、input 要素の type に number を指定するだけで作れます。これだけで、数字以外の文字はほとんど入力できなくなり、右端には値を増減できる上下の矢印(スピンボタン)が表示されます。何が何の入力欄かを伝えるため、label と結び付けておくのが基本です。
<label for="age">年齢</label>
<input type="number" id="age" name="age">
スピンボタンは1回押すごとに 1 ずつ値が変わります(この刻みは後述の step で変更できます)。なお、スピンボタンの見た目やクリックできる範囲はブラウザによって差があり、CSS で完全に統一するのは難しい点だけ覚えておくとよいでしょう。
min・max・step・value で範囲と刻みを決める
数値入力欄の挙動は、いくつかの属性で調整します。扱いたい値の範囲や、どれくらい細かく入力させるか、最初に表示しておく値などを指定できます。
| 属性 | 意味 |
|---|---|
min | 入力できる最小値 |
max | 入力できる最大値 |
step | スピンボタンの刻み幅・許可される値の間隔(既定は 1) |
value | 最初に表示しておく初期値 |
placeholder | 未入力のときに薄く表示する入力例 |
required | 送信時に必須(空だと送信できない)にする |
<!-- 1〜99 個を 1 刻みで、初期値 1、必須 -->
<input type="number" name="qty"
min="1" max="99" step="1" value="1" required>
ここで大切なのが step の考え方です。step は「スピンボタンで動く量」であると同時に、「入力を許可する値の間隔」でもあります。既定の step="1" のままだと整数しか有効な値になりません。12.5 のような小数を入れさせたいときは、step="0.5" や step="0.1" のように小数の刻みを指定する必要があります。刻みを気にせず任意の小数を受け付けたいときは、step="any" を指定します。step と合わない値は、後述する入力検証で「無効」と判定されます。
数量から小計を計算するデモ
実際に数値入力欄を使う例として、数量を入力すると小計が更新される簡単な計算フォームを見てみましょう。矢印ボタンや直接入力で数量を変えると、単価 × 数量 の結果が下に表示されます。値の取り出し方は次の節で詳しく説明します。
<label for="qty">数量:</label>
<input type="number" id="qty" name="qty" min="1" max="99" step="1" value="1">
<p>単価 300 円 × <output id="q">1</output> 個 =
<strong><output id="total">300</output> 円</strong></p>body {
font-family: sans-serif;
font-size: 15px;
}
label {
margin-right: 8px;
}
input[type="number"] {
width: 80px;
padding: 4px 6px;
font-size: 15px;
}
output {
font-weight: bold;
color: #2196f3;
}const qty = document.getElementById("qty");
const q = document.getElementById("q");
const total = document.getElementById("total");
const price = 300; // 単価
// 入力のたびに小計を計算して表示する
qty.addEventListener("input", () => {
// value は文字列なので valueAsNumber で数値として受け取る
const n = qty.valueAsNumber; // 空欄のときは NaN
const count = Number.isNaN(n) ? 0 : n;
q.textContent = count;
total.textContent = count * price;
});JavaScript で入力された数値を取得する
数値入力欄でつまずきやすいのが、値の取り出し方です。ほかの入力欄と同じく value プロパティで値を取れますが、type="number" であっても value が返すのは常に文字列です。そのため "5" + 1 のように書くと文字列の連結になり、"51" という予想外の結果になります。
const input = document.getElementById("qty");
// value は文字列で返る
console.log(input.value); // "5"(文字列)
console.log(typeof input.value); // "string"
// 数値として使いたいときの3つの方法
const a = input.valueAsNumber; // 5(数値)。空欄なら NaN
const b = Number(input.value); // 5(数値)。空欄なら 0
const c = parseFloat(input.value); // 5(数値)。空欄なら NaN
数値として扱う一番素直な方法は、valueAsNumber プロパティです。これは type="number"(や range など)で使え、値を最初から数値で返してくれます。ただし入力欄が空のときは NaN(数値でない値)になるため、計算前に Number.isNaN() でチェックしておくと安全です。文字列から変換する Number() や parseFloat() も使えますが、両者は空文字の扱いが異なります。Number("") は 0 を返すのに対し、parseFloat("") は NaN を返します。意図しない 0 を混入させたくない場面では、この違いに注意してください。
min・max・step で入力を検証する
min・max・step を指定すると、フォーム送信時にブラウザが自動で範囲や刻みをチェックし、外れていれば送信を止めてメッセージを表示します。この検証結果は、JavaScript から入力欄の validity(ValidityState オブジェクト)で確認できます。よく使うプロパティを挙げます。
| プロパティ | true になる状況 |
|---|---|
validity.rangeUnderflow | 値が min より小さい |
validity.rangeOverflow | 値が max より大きい |
validity.stepMismatch | 値が step の刻みに合っていない |
validity.badInput | 数値として解釈できない入力になっている |
validity.valueMissing | required なのに空である |
validity.valid | すべての制約を満たしている |
下のデモは、体重の入力欄に min="30"・max="200"・step="0.1" を指定し、入力のたびに validity を見てメッセージを出し分けています。範囲外の値や、刻みに合わない値を入れて、判定が変わる様子を確かめてみてください。
<label for="weight">体重 (kg):</label>
<input type="number" id="weight" name="weight"
min="30" max="200" step="0.1" placeholder="例: 62.5">
<p id="msg">30〜200 の範囲で、0.1 刻みで入力できます。</p>body {
font-family: sans-serif;
font-size: 15px;
}
label {
margin-right: 8px;
}
input[type="number"] {
width: 120px;
padding: 4px 6px;
font-size: 15px;
}
#msg {
color: #555;
}
#msg.error {
color: #d32f2f;
font-weight: bold;
}const input = document.getElementById("weight");
const msg = document.getElementById("msg");
// 入力のたびに検証状態を確認してメッセージを出し分ける
input.addEventListener("input", () => {
const v = input.validity; // ValidityState オブジェクト
if (v.rangeOverflow) {
msg.textContent = "大きすぎます(" + input.max + " 以下にしてください)";
msg.className = "error";
} else if (v.rangeUnderflow) {
msg.textContent = "小さすぎます(" + input.min + " 以上にしてください)";
msg.className = "error";
} else if (v.stepMismatch) {
msg.textContent = "0.1 刻みの値にしてください";
msg.className = "error";
} else if (input.value === "") {
msg.textContent = "30〜200 の範囲で、0.1 刻みで入力できます。";
msg.className = "";
} else {
msg.textContent = "OK: " + input.valueAsNumber + " kg";
msg.className = "";
}
});なお min・max は入力を「無効」と判定するだけで、キーボードからの入力そのものを禁止するわけではありません(スピンボタンは範囲内に収まります)。範囲外の値でも送信を確実に止めたい場合は、required と組み合わせて標準の検証に任せるか、上記のように JavaScript で validity をチェックして独自のメッセージを表示するとよいでしょう。
スマホの数値キーボードと inputmode
type="number" の利点のひとつが、スマートフォンで数字向けのキーボードが表示されやすいことです。文字入力用のキーボードから切り替える手間が省け、入力が快適になります。ただし、表示されるキーボードの種類は端末やブラウザによって差があります。より確実に狙ったキーボードを出したいときは、inputmode 属性で明示します。
| 指定 | 表示されるキーボード |
|---|---|
inputmode="numeric" | 整数向けの数字キー(小数点なし) |
inputmode="decimal" | 小数点付きの数字キー |
<!-- 小数を扱う入力欄では decimal を指定 -->
<input type="number" step="0.1" inputmode="decimal">
inputmode はあくまで「どのキーボードを出すか」の指定で、type="number" の検証の代わりにはなりません。範囲や刻みのチェックが必要なら min・max・step を別途付けてください。
type=”number” が向かない場面と落とし穴
type="number" は便利ですが、何でも数字の入力欄に使えばよいわけではありません。仕様上の性質から、かえって不便になる場面があります。
電話番号や郵便番号には向かない
電話番号や郵便番号は「数字の並び」であって「数値」ではありません。type="number" にすると、先頭の 0 が値として扱われず消えたり(0120... が 120... になるなど)、スピンボタンで意味なく増減できたり、桁数の多い番号が指数表記に化けたりします。こうした「数字の文字列」には、type="tel" を使い、必要なら pattern 属性で形式を指定するのが適しています。type="tel" ならスマホでも電話番号用のキーボードが出ます。
<!-- 電話番号は number ではなく tel + pattern が適する -->
<input type="tel" name="phone"
pattern="[0-9]{10,11}" inputmode="numeric">
空文字と指数表記の扱い
type="number" の value は、数値として解釈できない入力があると空文字("")を返す点にも注意が必要です。たとえば全角数字や記号を含む「不正な状態」では、画面には文字が残っていても JavaScript からは値が取れないことがあります。こうした状況は前述の validity.badInput で検知できます。また、1e5(=100000)のような指数表記も有効な数値として受け付けられるため、想定外の巨大な数が入る可能性がある点も頭に入れておきましょう。ユーザーが入れた文字列をそのまま保持したい用途では、type="text" に inputmode="numeric" を組み合わせる選択肢もあります。
まとめ
<input type="number"> は、数量や金額などの数値入力を手軽に作れる入力部品です。要点を整理します。
min・maxで範囲、stepで刻みを決める。小数はstep="0.1"やstep="any"で扱う。valueは文字列で返るため、計算にはvalueAsNumber/Number()/parseFloat()で数値に変換する。- 範囲や刻みの検証結果は
validity(rangeOverflowなど)で確認できる。 - スマホのキーボードは
inputmode="numeric"/"decimal"で狙って出せる。 - 電話番号など「数字の文字列」は
type="number"ではなくtype="tel"+patternが適する。
まずは min・max・step を指定した入力欄を置き、valueAsNumber で値を取り出して計算するところから始めると、数値入力の扱いがつかめます。