<input> は type の選び方で挙動が大きく変わります。この記事ではタイプ別に「そのまま使えるもの」「実務では避けるべきもの」を判断できるように整理します。typeごとの癖に加えて、<textarea>・<datalist>・field-sizing・accent-colorまでまとめて扱います。
この記事は2024年の公開後、2026年9月に見直しました。 公開当時のコードに、<textarea> に pattern 属性を指定するという誤りがありました。訂正したうえで、タイプ別の解説を追加しています。
pattern属性は<input>専用です。<textarea>では効きません。最小文字数を求めるならminlengthを使いますinputmode/autocomplete/list/patternはいずれも2024年の新機能ではありません
スポンサーリンク
type 別・使ってよいものと避けるべきもの
結論を先に言うと、number は用途を限定し、month と week は避けるのが無難です。date 系と range は、ブラウザ差を承知のうえで使う条件付きです。
| type | 判断 | 理由 |
|---|---|---|
text / email / tel / url / password |
そのまま使う | 挙動が安定している |
search |
使う | クリアボタンが付く |
date / time / datetime-local |
条件付き | UIがブラウザごとに大きく違う |
number |
用途を限定 | ホイールで値が変わる、先頭の0が落ちる |
range |
条件付き | 正確な値の入力には向かない |
color |
使う | OSのカラーピッカーが開く |
file |
使う | accept と capture が効く |
checkbox / radio |
使う | 標準のキーボード操作がそのまま使える |
month / week |
避ける | Firefox が未対応でただのテキスト欄になる |
判断に迷ったときは「その値は増減させるものか」「形式は国際的に一定か」の2点で考えると、選択を誤りにくくなります。以下、癖のあるものを順に見ていきます。
type=”date”:使う前に知っておくこと
表示形式はOSとブラウザのロケールで決まり、CSSでも属性でも変えられません。 日本語環境では「2024/06/09」、英語環境では「06/09/2024」のように表示されます。
<label for="birthday">生年月日</label>
<input type="date" id="birthday" name="birthday"
min="1900-01-01" max="2024-12-31"
autocomplete="bday">
知っておくべき点は3つです。
valueは必ずYYYY-MM-DD形式:表示がどうであれ、送信される値とJavaScriptから読む値はこの形ですmin/maxもYYYY-MM-DDで書く:範囲外は選べなくなります- 未入力時は空文字:
valueAsDateはnullを返します
日付の読み取りは valueAsDate に注意
const input = document.getElementById('birthday');
input.value; // "2024-06-09"(文字列)
input.valueAsDate; // Date オブジェクト。ただし UTC 基準
valueAsDate はUTCの午前0時として解釈されます。 日本時間で扱うと日付が1日ずれることがあるため、日付だけを扱うなら文字列のまま処理する方が安全です。
// ずれる可能性がある
const d = input.valueAsDate;
console.log(d.getDate()); // 環境によって前日になる
// 文字列のまま扱う
const [y, m, day] = input.value.split('-').map(Number);
なお、カレンダーを開くアイコンは小さく、スマートフォンでは押しづらい位置にあります。欄のどこを押してもピッカーが開くようにする showPicker() の使い方と制約は、HTMLフォームのバリデーションと送信にまとめています。
スポンサーリンク
type=”number”:使う場面を限定する
「数字を入れる欄」に無条件で使ってはいけません。 郵便番号・電話番号・クレジットカード番号には向きません。
- 先頭の
0が落ちる(0120→120) - ハイフンが入力できない
- マウスホイールで値が勝手に変わる
- 桁数の多い数値が指数表記になることがある
向くのは「増減させたい数値」、つまり数量や年齢のように上下させて調整するものだけです。その場合も min / max / step を必ず付けます。
<!-- 数量:これは type="number" が正しい -->
<label for="qty">数量</label>
<input type="number" id="qty" name="qty" value="1" min="1" max="99" step="1">
郵便番号のように「数字だが数量ではない」ものは type="text" にして、inputmode="numeric" でキーボードだけ数字に切り替えます。属性の組み合わせはinputmode・autocomplete・enterkeyhintでスマホの入力を速くするにまとめました。
ホイールでの誤操作は、フォーカス時にホイールを無効化して防げます。
document.querySelectorAll('input[type="number"]').forEach((el) => {
el.addEventListener('wheel', (e) => {
if (document.activeElement === el) e.preventDefault();
}, { passive: false });
});
{ passive: false } が必要です。付けないと preventDefault() が無視されます。
値を読むときは valueAsNumber が便利です。value は文字列なので、計算に使うなら変換が要ります。
const qty = document.getElementById('qty');
qty.value; // "1"(文字列)
qty.valueAsNumber; // 1(number。空なら NaN)
空欄のときは NaN になります。 Number.isNaN() で先に弾いてから計算してください。
type=”file”:accept と capture
type="file" は素直に使える type です。accept で選択ダイアログを絞り込み、capture でスマートフォンのカメラを直接起動できます。
<!-- 画像を複数選ぶ -->
<input type="file" name="photos" accept="image/*" multiple>
<!-- スマホで背面カメラを直接起動 -->
<input type="file" name="doc" accept="image/*" capture="environment">
<!-- 拡張子で絞る -->
<input type="file" name="sheet" accept=".csv,.xlsx,text/csv">
accept は検証ではありません。 ユーザーはダイアログで「すべてのファイル」に切り替えられます。種類とサイズは必ずサーバー側で確認してください。
capture の値は environment(背面カメラ)と user(前面カメラ)です。
選択後にクライアント側で弾く場合はこう書きます。
const MAX = 5 * 1024 * 1024; // 5MB
fileInput.addEventListener('change', () => {
for (const file of fileInput.files) {
if (!file.type.startsWith('image/')) {
alert('画像ファイルを選んでください');
fileInput.value = ''; // 選択を解除する
return;
}
if (file.size > MAX) {
alert('5MB以下のファイルを選んでください');
fileInput.value = '';
return;
}
}
});
fileInput.value = '' で選択を解除できます。 これを忘れると、無効なファイルが選ばれたままの表示が残ります。
スポンサーリンク
type=”color” と type=”range”
どちらも素直に使えます。color はOSのカラーピッカーが開き、range は list で目盛りを付けられます。注意点は range は現在値が見えないという1点です。
<label for="theme">テーマカラー</label>
<input type="color" id="theme" name="theme" value="#2a7fff">
<label for="volume">音量</label>
<input type="range" id="volume" name="volume"
min="0" max="100" step="5" value="50"
list="volume-marks">
<datalist id="volume-marks">
<option value="0"></option>
<option value="50"></option>
<option value="100"></option>
</datalist>
<output for="volume" id="volume-out">50</output>
type="range" に list を付けると目盛りが表示されます。また、range は現在値が見えないので、<output> を必ず添えてください。
const volume = document.getElementById('volume');
const out = document.getElementById('volume-out');
volume.addEventListener('input', () => {
out.textContent = volume.value;
});
input イベントと change イベントの違いに注意してください。input はつまみを動かしている間ずっと発火し、change は離したときだけ発火します。表示の更新は input、サーバーへの保存は change が適切です。
チェックボックスやスライダーの色は accent-color で変える
チェックボックス・ラジオ・range・progress の色は、長らく appearance: none で作り直すしかありませんでした。accent-color を使えば1行です。
:root {
accent-color: #2a7fff;
}
ブラウザ標準の見た目・キーボード操作・アクセシビリティをそのまま保ったまま、ブランドカラーだけ差し替えられます。見た目のためだけに appearance: none で自作するのは、フォーカスリングやスクリーンリーダー対応まで自分で再実装することになるので、まずこちらを試してください。
トグルスイッチは switch 属性を使えるか
まだ本番では使えません。 <input type="checkbox" switch> は Safari 17.4 で搭載されましたが、2026年9月時点でChrome と Firefox は未対応です。
ただし、未対応ブラウザでは普通のチェックボックスとして正しく動作するため、段階的強化として書いておくのは安全です。
<label>
<input type="checkbox" switch name="notify" checked>
通知を受け取る
</label>
全ブラウザで同じ見た目のスイッチが必要なら、現状はCSSで作ることになります。その場合も appearance: none で作り直すより、accent-color で色だけ変えたチェックボックスの方が、キーボード操作とスクリーンリーダー対応の面では堅実です。
textarea には pattern が効かない
公開当時のコードにあった誤りです。 pattern 属性は <input> だけのもので、<textarea> には存在しません。
<!-- 効かない -->
<textarea required pattern=".{10,}" title="10文字以上"></textarea>
<!-- 正しい:minlength を使う -->
<label for="feedback">フィードバック</label>
<textarea id="feedback" name="feedback"
required minlength="10" maxlength="1000"
placeholder="ご意見をお聞かせください"></textarea>
minlength の注意点:ユーザーが一度も入力していない状態では発動せず、required の方が先に効きます。また、改行は1文字として数えられます。
高さの自動調整は field-sizing で1行になる
入力量に応じて高さを自動調整する処理は、これまでJavaScriptで scrollHeight を測って書いていました。CSSの field-sizing: content で1行になります。 2026年6月に Baseline 入りしました。
textarea {
field-sizing: content;
min-height: 4lh; /* 最低4行分は確保する */
max-height: 20lh; /* 伸びすぎを防ぐ */
width: 100%;
}
input[type="text"] {
field-sizing: content;
min-width: 8ch;
}
min-height と max-height をセットで指定するのがコツです。指定しないと、空のときに1行分まで縮み、長文で画面いっぱいまで伸びます。lh 単位(1行の高さ)を使うと行数で指定できて分かりやすいです。
残り文字数を出すなら、maxlength と組み合わせます。
const ta = document.getElementById('feedback');
const counter = document.getElementById('counter');
ta.addEventListener('input', () => {
counter.textContent = `${ta.value.length} / ${ta.maxLength}`;
});
datalist は候補以外も入力できる
<datalist> は手軽な入力補完ですが、「候補以外も入力できてしまう」点を理解しておく必要があります。選択肢を強制したいなら <select> を使ってください。
<label for="search">商品を検索</label>
<input type="search" id="search" list="products"
enterkeyhint="search" placeholder="商品名を入力">
<datalist id="products">
<option value="スマートフォン"></option>
<option value="ノートパソコン"></option>
<option value="タブレット"></option>
<option value="ヘッドフォン"></option>
</datalist>
実際に使うときに知っておきたい制約です。
- 候補以外の値も送信できる:弾きたいなら
patternかサーバー側で検証する - 候補リストの見た目はCSSで変えられない:ブラウザのUIそのものです
- 絞り込み方式はブラウザ依存:前方一致か部分一致かが統一されていません
- 件数が多いと使いづらい:数十件を超えるなら
<select>か自作のコンボボックスへ
都道府県のように選択肢が固定で、かつ自由入力を許したくないものは <select> が正解です。<datalist> が向くのは、商品名の検索のように候補が参考情報でよい場面です。
実装例:type を選び終えたフォーム
ここまでの内容をまとめた形です。
<form>
<label for="username">ユーザー名</label>
<input type="text" id="username" name="username"
required autocomplete="username" minlength="3">
<label for="email">メールアドレス</label>
<input type="email" id="email" name="email"
required autocomplete="email">
<label for="password">パスワード</label>
<input type="password" id="password" name="password"
required autocomplete="new-password" minlength="8">
<label for="birthdate">生年月日</label>
<input type="date" id="birthdate" name="birthdate"
required autocomplete="bday" max="2024-12-31">
<label for="phone">電話番号</label>
<input type="tel" id="phone" name="phone"
autocomplete="tel" inputmode="tel"
pattern="0\d{1,4}-?\d{1,4}-?\d{4}"
title="例: 090-1234-5678">
<button type="submit">登録</button>
</form>
type の選び方として押さえたいのは次の3点です。
- ユーザー名・パスワードは
textとpassword:長さの制約はminlengthで書く - 生年月日は
date:min/maxで選べる範囲を絞る。読み取りは文字列のまま扱う - 電話番号は
tel:形式が国ごとに違うため、ブラウザ側の検証はありません。patternで補います
この先、エラーの出し方と送信の制御はHTMLフォームのバリデーションと送信にまとめています。autocomplete と inputmode の正しい値はinputmode・autocomplete・enterkeyhintでスマホの入力を速くするを参照してください。
まとめ
patternは<input>専用。<textarea>にはminlengthtype="date"のvalueは常にYYYY-MM-DD。valueAsDateはUTC基準でずれるtype="number"は「増減させる数量」だけに使う。 郵便番号や電話番号には使わないtype="number"のホイール誤操作は{ passive: false }付きで無効化する。値はvalueAsNumberで読む(空ならNaN)acceptは検証ではない。サーバー側の確認が必須。value = ''で選択解除できるtype="range"には<output>を添える。表示更新はinput、保存はchange- 部品の色は
accent-color。appearance: noneで自作しない。switch属性はSafariのみ - 高さの自動調整は
field-sizing: content。min-heightとmax-heightをセットで書く <datalist>は候補以外も入力できる。強制したいなら<select>month/weekは Firefox が未対応なので避ける
type を1つ選び間違えるだけで、ユーザーが入力できない欄ができてしまいます。「その値は増減させるものか」「形式は国際的に一定か」の2点で判断すると、選択を誤りにくくなります。